diff --git a/.github/Dependabot.yml b/.github/Dependabot.yml index 039747b..63e673a 100644 --- a/.github/Dependabot.yml +++ b/.github/Dependabot.yml @@ -1,4 +1,4 @@ -# Dependabot configuration for <%= $PLASTER_PARAM_ModuleName %> +# Dependabot configuration for AsBuiltReport.Microsoft.Azure # https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file version: 2 diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 7838e9c..c343501 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -90,7 +90,7 @@ body: I have read and followed the [bug reporting guidelines](https://www.asbuiltreport.com/dev-guide/contributing/#reporting-issues-and-bugs). required: true - label: >- - I have read [the documentation](https://www.asbuiltreport.com/user-guide/quickstart/, + I have read [the documentation](https://www.asbuiltreport.com/user-guide/quickstart/), and referred to the [known issues](https://www.asbuiltreport.com/support/known-issues/) before submitting this bug report. required: true - label: >- diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 2ba6427..6622e9b 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -28,7 +28,7 @@ ## Checklist: -- [ ] My code follows the [code style](https://www.asbuiltreport.com/about/contributing/#use-a-consistent-coding-style) of this project. +- [ ] My code follows the [code style](https://www.asbuiltreport.com/dev-guide/contributing/#coding-style-guidelines) of this project. - [ ] My change requires a change to the documentation. - [ ] I have updated the documentation accordingly. -- [ ] I have read the [contributing](https://www.asbuiltreport.com/about/contributing/) documentation. +- [ ] I have read the [contributing](https://www.asbuiltreport.com/dev-guide/contributing/) documentation. diff --git a/.github/workflows/DraftRelease.yml b/.github/workflows/DraftRelease.yml new file mode 100644 index 0000000..b0da543 --- /dev/null +++ b/.github/workflows/DraftRelease.yml @@ -0,0 +1,50 @@ +name: Create Draft Release + +on: + push: + tags: + - 'v*' + +jobs: + draft-release: + name: Create Draft GitHub Release + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Verify tag is on main or master + id: verify + run: | + if git merge-base --is-ancestor "${{ github.sha }}" origin/main 2>/dev/null || \ + git merge-base --is-ancestor "${{ github.sha }}" origin/master 2>/dev/null; then + echo "on_main=true" >> $GITHUB_OUTPUT + else + echo "Tag is not on main/master — skipping release creation." + echo "on_main=false" >> $GITHUB_OUTPUT + fi + + - name: Extract release notes from CHANGELOG + if: steps.verify.outputs.on_main == 'true' + shell: pwsh + run: | + $changelog = Get-Content -Path CHANGELOG.md -Raw + # Match content between the first ## [ heading and the next one + if ($changelog -match '(?s)(## \[\d+\.\d+\.\d+\].*?)(?=\r?\n## \[|\z)') { + $Matches[1].Trim() | Set-Content -Path release-notes.md -NoNewline + } else { + "No changelog entry found for this release." | Set-Content -Path release-notes.md + } + + - name: Create draft release + if: steps.verify.outputs.on_main == 'true' + uses: softprops/action-gh-release@v2 + with: + draft: true + make_latest: false + body_path: release-notes.md diff --git a/.github/workflows/PSScriptAnalyzer.yml b/.github/workflows/PSScriptAnalyzer.yml index d7a7e8d..413d575 100644 --- a/.github/workflows/PSScriptAnalyzer.yml +++ b/.github/workflows/PSScriptAnalyzer.yml @@ -5,9 +5,9 @@ jobs: name: Run PSScriptAnalyzer runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v6 - name: lint - uses: devblackops/github-action-psscriptanalyzer@master + uses: alagoutte/github-action-psscriptanalyzer@master with: sendComment: true failOnErrors: true diff --git a/.github/workflows/Pester.yml b/.github/workflows/Pester.yml index 0a00ab6..f892c73 100644 --- a/.github/workflows/Pester.yml +++ b/.github/workflows/Pester.yml @@ -59,6 +59,10 @@ jobs: run: | Install-Module -Name AsBuiltReport.Core -MinimumVersion 1.6.0 -Repository PSGallery -Force -AllowClobber -Scope CurrentUser + - name: Install AsBuiltReport.Diagram + run: | + Install-Module -Name AsBuiltReport.Diagram -MinimumVersion 1.0.8 -Repository PSGallery -Force -AllowClobber -Scope CurrentUser + - name: Run Pester Tests run: | $CodeCoverageParam = @{} diff --git a/AsBuiltReport.Microsoft.Azure/AsBuiltReport.Microsoft.Azure.json b/AsBuiltReport.Microsoft.Azure/AsBuiltReport.Microsoft.Azure.json index 431f254..9552a1f 100644 --- a/AsBuiltReport.Microsoft.Azure/AsBuiltReport.Microsoft.Azure.json +++ b/AsBuiltReport.Microsoft.Azure/AsBuiltReport.Microsoft.Azure.json @@ -12,27 +12,50 @@ "Options": { "ShowSectionInfo": true, "ShowTags": true, + "EnableDiagrams": true, + "DiagramTheme": "White", + "DiagramDpi": 600, + "NvaPublishers": ["fortinet"], + "NvaTag": "", "SectionOrder": [ + "ApplicationGateway", "StorageAccount", "KeyVault", "LogAnalyticsWorkspace", + "DataCollectionRule", + "DiagnosticSetting", "LoadBalancer", "ExpressRoute", + "VirtualNetworkGateway", + "DdosProtectionPlan", "VirtualNetwork", + "PublicIpAddress", + "NetworkWatcher", "NetworkSecurityGroup", "PrivateEndpoint", "IpGroup", "DnsPrivateResolver", + "DnsForwardingRuleset", + "PrivateDnsZone", "Bastion", "Policy", + "UserAssignedManagedIdentity", "Firewall", "FirewallPolicy", "RouteTable", + "NetworkVirtualAppliance", "VirtualMachine", "AvailabilitySet", + "VmScaleSet", + "MaintenanceConfiguration", + "AutomationAccount", "RecoveryServicesVault", "SiteRecovery", - "DesktopVirtualization" + "AsrPolicy", + "AsrRecoveryPlan", + "AsrNetworkMapping", + "DesktopVirtualization", + "NetAppFiles" ] }, "Filter": { @@ -40,36 +63,88 @@ }, "InfoLevel": { "_comment_": "0 = Disabled, 1 = Enabled / Summary, 2 = Detailed, 3 = Adv. Detailed, 4 = Comprehensive", + "ApplicationGateway": 1, + "AsrNetworkMapping": 1, + "AsrPolicy": 1, + "AsrRecoveryPlan": 1, + "AutomationAccount": 1, "AvailabilitySet": 1, "Bastion": 1, + "DataCollectionRule": 1, + "DdosProtectionPlan": 1, + "DesktopVirtualization": 1, + "DiagnosticSetting": 1, + "DnsForwardingRuleset": 1, "DnsPrivateResolver": 1, "ExpressRoute": 1, "Firewall": 1, "FirewallPolicy": 1, "IpGroup": 1, "KeyVault": 1, - "LogAnalyticsWorkspace": 1, "LoadBalancer": 1, + "LogAnalyticsWorkspace": 1, + "MaintenanceConfiguration": 1, + "ManagementGroup": 1, + "NetAppFiles": 1, "NetworkSecurityGroup": 1, + "NetworkVirtualAppliance": 1, + "NetworkWatcher": 1, "Policy": { "Assignments": 1, "Definitions": 0 }, + "PrivateDnsZone": 1, "PrivateEndpoint": 2, + "PublicIpAddress": 1, "RecoveryServicesVault": 1, "RouteTable": 1, "SiteRecovery": 1, "StorageAccount": 1, "Subscription": 1, "Tenant": 0, - "VirtualNetwork": 1, + "UserAssignedManagedIdentity": 1, "VirtualMachine": 1, - "DesktopVirtualization": 1 + "VirtualNetwork": 1, + "VirtualNetworkGateway": 1, + "VmScaleSet": 1 }, "HealthCheck": { + "ApplicationGateway": { + "ProvisioningState": true, + "OperationalState": true + }, + "AsrNetworkMapping": { + "MappingState": true + }, + "AsrPolicy": { + "AppConsistentSnapshot": true + }, + "AutomationAccount": { + "State": true + }, "Bastion": { "ProvisioningState": true }, + "DataCollectionRule": { + "ProvisioningState": true + }, + "DdosProtectionPlan": { + "ProvisioningState": true + }, + "DesktopVirtualization": { + "SessionHostHealth": true, + "DrainMode": true, + "RegistrationExpiry": true, + "NoSessionHosts": true, + "HostPoolCapacity": true + }, + "DiagnosticSetting": { + "NoLogsEnabled": true + }, + "DnsForwardingRuleset": { + "ProvisioningState": true, + "ForwardingRuleState": true + }, "DnsPrivateResolver": { "ProvisioningState": true, "CurrentState": true @@ -101,25 +176,46 @@ "PublicNetworkAccessForIngestion": true, "PublicNetworkAccessForQuery": true }, + "NetAppFiles": { + "PoolCapacity": true, + "AdHealth": true, + "SnapshotPolicy": true, + "BackupProtection": true, + "CustomerManagedKey": true + }, "NetworkSecurityGroup": { "ProvisioningState": true, "OverlyPermissiveRules": true }, + "NetworkVirtualAppliance": { + "Status": true + }, + "NetworkWatcher": { + "ProvisioningState": true, + "FlowLogEnabled": true + }, + "PrivateDnsZone": { + "ProvisioningState": true, + "VirtualNetworkLinks": true + }, "PrivateEndpoint": { "ProvisioningState": true, "ConnectionStatus": true }, + "PublicIpAddress": { + "ProvisioningState": true, + "Unattached": true + }, "RecoveryServicesVault": { "ProvisioningState": true, - "PrivateEndpointStateForBackup": true + "PrivateEndpointStateForBackup": true, + "SoftDeleteEnabled": true, + "ImmutabilityEnabled": true, + "PublicNetworkAccess": true }, "RouteTable": { "ProvisioningState": true }, - "SiteRecovery": { - "ReplicationHealth": true, - "FailoverHealth": true - }, "StorageAccount": { "ProvisioningState": true, "StorageAccountKeyAccess": true, @@ -128,6 +224,11 @@ "PublicNetworkAccess": true, "MinimumTlsVersion": true }, + "SiteRecovery": { + "ReplicationHealth": true, + "FailoverHealth": true, + "NoTestFailover": true + }, "VirtualMachine": { "Status": true, "DiskEncryption": true, @@ -138,12 +239,12 @@ "ProvisioningState": true, "DnsServers": true }, - "DesktopVirtualization": { - "SessionHostHealth": true, - "DrainMode": true, - "RegistrationExpiry": true, - "NoSessionHosts": true, - "HostPoolCapacity": true + "VirtualNetworkGateway": { + "ProvisioningState": true, + "ConnectionStatus": true + }, + "VmScaleSet": { + "ProvisioningState": true } } } diff --git a/AsBuiltReport.Microsoft.Azure/AsBuiltReport.Microsoft.Azure.psd1 b/AsBuiltReport.Microsoft.Azure/AsBuiltReport.Microsoft.Azure.psd1 index 26d39c2..4892449 100644 --- a/AsBuiltReport.Microsoft.Azure/AsBuiltReport.Microsoft.Azure.psd1 +++ b/AsBuiltReport.Microsoft.Azure/AsBuiltReport.Microsoft.Azure.psd1 @@ -12,7 +12,7 @@ RootModule = 'AsBuiltReport.Microsoft.Azure.psm1' # Version number of this module. -ModuleVersion = '0.2.0' +ModuleVersion = '0.3.0' # Supported PSEditions CompatiblePSEditions = @('Desktop', 'Core') @@ -54,7 +54,11 @@ PowerShellVersion = '5.1' RequiredModules = @( @{ ModuleName = 'AsBuiltReport.Core'; - ModuleVersion = '1.6.1' + ModuleVersion = '1.6.4' + }, + @{ + ModuleName = 'AsBuiltReport.Diagram'; + ModuleVersion = '1.0.8' } ) @@ -109,7 +113,7 @@ PrivateData = @{ ProjectUri = 'https://github.com/AsBuiltReport/AsBuiltReport.Microsoft.Azure' # A URL to an icon representing this module. - IconUri = 'https://raw.githubusercontent.com/AsBuiltReport/.github/main/profile/images/AsBuiltReport.png' + # IconUri = 'https://raw.githubusercontent.com/AsBuiltReport/.github/main/profile/images/AsBuiltReport.png' # ReleaseNotes of this module ReleaseNotes = 'https://raw.githubusercontent.com/AsBuiltReport/AsBuiltReport.Microsoft.Azure/master/CHANGELOG.md' @@ -121,7 +125,7 @@ PrivateData = @{ # RequireLicenseAcceptance = $false # External dependent modules of this module - ExternalModuleDependencies = @('AsBuiltReport.Core', 'Az') + ExternalModuleDependencies = @('Az') } # End of PSData hashtable diff --git a/AsBuiltReport.Microsoft.Azure/AsBuiltReport.Microsoft.Azure.psm1 b/AsBuiltReport.Microsoft.Azure/AsBuiltReport.Microsoft.Azure.psm1 index e22b0dc..3c92570 100644 --- a/AsBuiltReport.Microsoft.Azure/AsBuiltReport.Microsoft.Azure.psm1 +++ b/AsBuiltReport.Microsoft.Azure/AsBuiltReport.Microsoft.Azure.psm1 @@ -1,8 +1,10 @@ # Get public and private function definition files and dot source them $Public = @(Get-ChildItem -Path $PSScriptRoot\Src\Public\*.ps1 -ErrorAction SilentlyContinue) -$Private = @(Get-ChildItem -Path $PSScriptRoot\Src\Private\*.ps1 -ErrorAction SilentlyContinue) +$Diagram = @(Get-ChildItem -Path $PSScriptRoot\Src\Private\Diagram\*.ps1 -ErrorAction SilentlyContinue) +$Report = @(Get-ChildItem -Path $PSScriptRoot\Src\Private\Report\*.ps1 -ErrorAction SilentlyContinue) -foreach ($Module in @($Public + $Private)) { + +foreach ($Module in @($Public + $Diagram + $Report)) { try { . $Module.FullName } catch { @@ -11,4 +13,5 @@ foreach ($Module in @($Public + $Private)) { } Export-ModuleMember -Function $Public.BaseName -Export-ModuleMember -Function $Private.BaseName \ No newline at end of file +Export-ModuleMember -Function $Diagram.BaseName +Export-ModuleMember -Function $Report.BaseName \ No newline at end of file diff --git a/AsBuiltReport.Microsoft.Azure/Icons/blank.png b/AsBuiltReport.Microsoft.Azure/Icons/blank.png new file mode 100644 index 0000000..9e93e44 Binary files /dev/null and b/AsBuiltReport.Microsoft.Azure/Icons/blank.png differ diff --git a/AsBuiltReport.Microsoft.Azure/Icons/management-groups.png b/AsBuiltReport.Microsoft.Azure/Icons/management-groups.png new file mode 100644 index 0000000..22e2044 Binary files /dev/null and b/AsBuiltReport.Microsoft.Azure/Icons/management-groups.png differ diff --git a/AsBuiltReport.Microsoft.Azure/Icons/subscriptions.png b/AsBuiltReport.Microsoft.Azure/Icons/subscriptions.png new file mode 100644 index 0000000..6d83882 Binary files /dev/null and b/AsBuiltReport.Microsoft.Azure/Icons/subscriptions.png differ diff --git a/AsBuiltReport.Microsoft.Azure/Language/de-DE/MicrosoftAzure.psd1 b/AsBuiltReport.Microsoft.Azure/Language/de-DE/MicrosoftAzure.psd1 index edb8f7a..710bc0e 100644 --- a/AsBuiltReport.Microsoft.Azure/Language/de-DE/MicrosoftAzure.psd1 +++ b/AsBuiltReport.Microsoft.Azure/Language/de-DE/MicrosoftAzure.psd1 @@ -11,6 +11,7 @@ InvokeAsBuiltReportMicrosoftAzure = ConvertFrom-StringData @' InfoLevelNotFound = InfoLevel für '{0}' nicht gefunden. FunctionNotFound = Funktion '{0}' für Abschnitt '{1}' nicht gefunden. SectionError = Fehler bei der Verarbeitung des Abschnitts '{0}': {1}" + AzureApiError = Azure-API-Aufruf fehlgeschlagen: {0} TenantNotFound = Azure-Mandant '{0}' nicht gefunden. TokenAccountIdRequired = Azure-Token-Authentifizierung erfordert den AccountId-Parameter. Verwenden Sie {0} mit {1} @{{AccountId="benutzer@domain.com"}}. ConnectingWithToken = Verbindung zu Azure mit Token für Konto {0} im Mandanten {1} wird hergestellt. @@ -288,7 +289,7 @@ GetAbrAsrProtectedItems = ConvertFrom-StringData @' InfoLevel = SiteRecovery-InfoLevel auf {0} gesetzt. Collecting = Azure Site Recovery-Informationen '{0}' werden gesammelt. CollectingItems = Azure Site Recovery geschützte Elemente werden gesammelt. - ParagraghSummary = Die folgenden Tabellen enthalten Informationen zu den geschützten Azure Site Recovery-Elementen im Abonnement {0}. + ParagraphSummary = Die folgende Tabelle enthält Informationen zu den geschützten Azure Site Recovery-Elementen im Abonnement {0}. Heading = Geschützte Elemente TableHeading = Geschützte Elemente SubHeading = Site Recovery @@ -301,6 +302,69 @@ GetAbrAsrProtectedItems = ConvertFrom-StringData @' ActiveLocation = Aktiver Standort TargetLocation = Zielstandort FailoverHealth = Failover-Zustand + NoTestFailover = Es wurde kein Test-Failover durchgeführt + ParagraphDetail = Die folgenden Abschnitte beschreiben die Konfiguration der geschützten Azure Site Recovery-Elemente im Abonnement {0}. + ReplicationProvider = Replikationsanbieter + Rpo = RPO (Min.) + LastRpoCalculated = Letzte RPO-Berechnung + LastHeartbeat = Letzter Heartbeat + RecoveryVmSize = Größe der Wiederherstellungs-VM + RecoveryAvailabilityZone = Verfügbarkeitszone der Wiederherstellung + NotAvailable = N/V + None = Keine +'@ + +# Azure Site Recovery Replikationsrichtlinien (Get-AbrAzAsrPolicy) +GetAbrAzAsrPolicy = ConvertFrom-StringData @' + InfoLevel = AsrPolicy-InfoLevel auf {0} gesetzt. + Collecting = Azure Site Recovery-Richtlinieninformationen für '{0}' werden gesammelt. + SectionInfo = Azure Site Recovery-Replikationsrichtlinien definieren Recovery Point Objectives (RPO) und den Wiederherstellungspunktverlauf für replizierte virtuelle Maschinen. + Heading = Replikationsrichtlinien + TableHeadings = Replikationsrichtlinien + ParagraphSummary = Die folgende Tabelle fasst die Azure Site Recovery-Replikationsrichtlinien zusammen, die für den Recovery Services-Tresor {0} konfiguriert sind. + ParagraphDetail = Die folgenden Abschnitte beschreiben die Azure Site Recovery-Replikationsrichtlinien, die für den Recovery Services-Tresor {0} konfiguriert sind. + Name = Name + Provider = Anbieter + RpoThreshold = RPO-Schwellenwert (Min.) + RecoveryPointHistory = Wiederherstellungspunktverlauf (Std.) + AppConsistentFrequency = App-konsistente Momentaufnahme (Min.) + CrashConsistentFrequency = Absturzkonsistente Momentaufnahme (Min.) + MultiVmSync = Multi-VM-Synchronisierung + NotApplicable = N/V +'@ + +# Azure Site Recovery Wiederherstellungspläne (Get-AbrAzAsrRecoveryPlan) +GetAbrAzAsrRecoveryPlan = ConvertFrom-StringData @' + InfoLevel = AsrRecoveryPlan-InfoLevel auf {0} gesetzt. + Collecting = Azure Site Recovery-Wiederherstellungsplaninformationen für '{0}' werden gesammelt. + SectionInfo = Azure Site Recovery-Wiederherstellungspläne koordinieren das Failover und die Wiederherstellung von Gruppen virtueller Maschinen und ermöglichen koordinierte DR-Vorgänge. + Heading = Wiederherstellungspläne + TableHeadings = Wiederherstellungspläne + ParagraphSummary = Die folgende Tabelle fasst die Azure Site Recovery-Wiederherstellungspläne zusammen, die für den Recovery Services-Tresor {0} konfiguriert sind. + ParagraphDetail = Die folgenden Abschnitte beschreiben die Azure Site Recovery-Wiederherstellungspläne, die für den Recovery Services-Tresor {0} konfiguriert sind. + Name = Name + PrimaryFabric = Primärer Standort + RecoveryFabric = Wiederherstellungsstandort + GroupCount = Gruppen + ProtectedItemCount = Geschützte Elemente + FailoverDeploymentModel = Failover-Bereitstellungsmodell + None = Keine +'@ + +# Azure Site Recovery Netzwerkzuordnungen (Get-AbrAzAsrNetworkMapping) +GetAbrAzAsrNetworkMapping = ConvertFrom-StringData @' + InfoLevel = AsrNetworkMapping-InfoLevel auf {0} gesetzt. + Collecting = Azure Site Recovery-Netzwerkzuordnungsinformationen für '{0}' werden gesammelt. + SectionInfo = Azure Site Recovery-Netzwerkzuordnungen definieren die Beziehung zwischen Quell- und Zielnetzwerken, die bei Failover-Vorgängen verwendet werden. + Heading = Netzwerkzuordnungen + TableHeadings = Netzwerkzuordnungen + ParagraphSummary = Die folgende Tabelle fasst die Azure Site Recovery-Netzwerkzuordnungen zusammen, die für den Recovery Services-Tresor {0} konfiguriert sind. + ParagraphDetail = Die folgenden Abschnitte beschreiben die Azure Site Recovery-Netzwerkzuordnungen, die für den Recovery Services-Tresor {0} konfiguriert sind. + Name = Name + PrimaryNetwork = Primäres Netzwerk + RecoveryNetwork = Wiederherstellungsnetzwerk + MappingState = Zuordnungsstatus + None = Keine '@ # Azure Availability Sets (Get-AbrAzAvailabilitySet) @@ -422,6 +486,7 @@ GetAbrAzStorageAccount = ConvertFrom-StringData @' Disabled = Deaktiviert Unknown = Unbekannt Created = Erstellt + Locks = Sperren Tags = Tags None = Keine '@ @@ -484,6 +549,7 @@ GetAbrAzFirewall = ConvertFrom-StringData @' NatRules = NAT-Regeln NetworkRules = Netzwerkregeln AppRules = Anwendungsregeln + Locks = Sperren Tags = Tags None = Keine '@ @@ -592,6 +658,7 @@ GetAbrAzKeyVault = ConvertFrom-StringData @' Disabled = Deaktiviert NoAccessEnabled = Kein Zugriff aktiviert EnabledDays = Aktiviert ({0} Tage) + Locks = Sperren Tags = Tags None = Keine days = Tage @@ -665,7 +732,7 @@ GetAbrAzLoadBalancer = ConvertFrom-StringData @' Heading = Load Balancer TableHeading = Load Balancer TableHeadings = Load Balancer - LoadBalancerImage = Load Balancer-Bild + Image = Load Balancer-Bild ImageError = Load Balancer-Bild kann nicht angezeigt werden Name = Name ResourceGroup = Ressourcengruppe @@ -715,6 +782,7 @@ GetAbrAzLogAnalyticsWorkspace = ConvertFrom-StringData @' Disabled = Deaktiviert Unknown = Unbekannt NoQuota = Kein Kontingent festgelegt + Locks = Sperren Tags = Tags None = Keine '@ @@ -859,6 +927,13 @@ GetAbrAzRecoveryServicesVault = ConvertFrom-StringData @' ProvisioningState = Bereitstellungsstatus PrivateEndpointStateForBackup = Privater Endpunktstatus für Sicherung PrivateEndpointStateForSiteRecovery = Privater Endpunktstatus für Site Recovery + StorageRedundancy = Speicherredundanz + CrossRegionRestore = Regionsübergreifende Wiederherstellung + SoftDeleteState = Status des vorläufigen Löschens + SoftDeleteRetentionDays = Aufbewahrung bei vorläufigem Löschen (Tage) + ImmutabilityState = Unveränderlichkeitsstatus + PublicNetworkAccess = Öffentlicher Netzwerkzugang + Locks = Sperren Tags = Tags None = Keine '@ @@ -883,6 +958,7 @@ GetAbrAzRouteTable = ConvertFrom-StringData @' AddressPrefix = Adresspräfix NextHopType = Nächster Hop-Typ NextHopIpAddress = Nächste Hop-IP-Adresse + Locks = Sperren Tags = Tags None = Keine '@ @@ -1063,6 +1139,7 @@ GetAbrAzVirtualNetwork = ConvertFrom-StringData @' Subnets = Subnetze DnsServers = DNS-Server Default = Standard (von Azure bereitgestellt) + Locks = Sperren Tags = Tags None = Keine '@ @@ -1254,4 +1331,588 @@ GetAbrAzDesktopVirtualization = ConvertFrom-StringData @' Allowed = Erlaubt '@ + +# Azure NetApp Files (Get-AbrAzNetAppFiles) +GetAbrAzNetAppFiles = ConvertFrom-StringData @' + InfoLevel = NetAppFiles-InfoLevel auf {0} festgelegt. + Collecting = Azure NetApp Files-Informationen werden gesammelt. + SectionInfo = Azure NetApp Files ist ein leistungsstarker, kostenpflichtiger Dateispeicherdienst der Enterprise-Klasse, der in Azure ausgeführt wird. Er unterstützt SMB, NFSv3, NFSv4.1 und Volumes mit dualem Protokoll, einschließlich integrierter Snapshots, regionsübergreifender Replikation und Sicherung. + AccountsSummary = Die folgende Tabelle fasst die NetApp Files-Konten im Abonnement {0} zusammen. + PoolsSummary = Die folgende Tabelle fasst die Kapazitätspools im Abonnement {0} zusammen. + VolumesSummary = Die folgende Tabelle fasst die Volumes im Abonnement {0} zusammen. + SnapshotPoliciesSummary = Die folgende Tabelle fasst die Snapshot-Richtlinien im Abonnement {0} zusammen. + BackupPoliciesSummary = Die folgende Tabelle fasst die Sicherungsrichtlinien im Abonnement {0} zusammen. + AdConfigIntro = Active Directory-Konfiguration für NetApp-Konto '{0}'. + MountTargetsIntro = Bereitstellungsziele für Volume '{0}'. + WarningPoolAllocation = WARNUNG: Kapazitätspool '{0}' ist zu {1}% belegt ({2} GiB von {3} GiB). + WarningAdStatus = WARNUNG: Active Directory-Konfiguration für Konto '{0}' hat den Status '{1}'. + Heading = Azure NetApp Files + AccountsHeading = NetApp-Konten + PoolsHeading = Kapazitätspools + VolumesHeading = Volumes + SnapshotPoliciesHeading = Snapshot-Richtlinien + BackupPoliciesHeading = Sicherungsrichtlinien + ActiveDirectoryHeading = Active Directory-Konfiguration + EncryptionHeading = Verschlüsselungskonfiguration + ExportPolicyHeading = Exportrichtlinienregeln + MountTargetsHeading = Bereitstellungsziele + DataProtectionHeading = Datensicherung + SnapshotsHeading = Snapshots + QuotaRulesHeading = Volumekontingentregeln + Name = Name + ResourceGroup = Ressourcengruppe + Location = Standort + Tags = Tags + Status = Status + Type = Typ + Account = Konto + Pool = Pool + Volume = Volume + ServiceLevel = Dienstebene + QosType = QoS-Typ + SizeTiB = Größe (TiB) + SizeGiB = Größe (GiB) + QuotaGiB = Kontingent (GiB) + AllocatedGiB = Zugewiesen (GiB) + PercentAllocated = % Zugewiesen + VolumeCount = Volumes + TotalThroughput = Gesamtdurchsatz (MiB/s) + UtilizedThroughput = Genutzter Durchsatz (MiB/s) + CoolAccess = Kalter Zugriff + EncryptionType = Verschlüsselungstyp + EncryptionKeySource = Verschlüsselungsschlüsselquelle + EncryptionKeyVault = Key Vault-URI + EncryptionKeyName = Schlüsselname + Protocol = Protokoll + Subnet = Delegiertes Subnetz + Zone = Verfügbarkeitszone + Throughput = Durchsatz (MiB/s) + ActualThroughput = Tatsächlicher Durchsatz (MiB/s) + SecurityStyle = Sicherheitsstil + UnixPermission = Unix-Berechtigungen + SnapshotPolicy = Snapshot-Richtlinie + BackupPolicy = Sicherungsrichtlinie + SnapshotDirVisible = Snapshot-Verzeichnis sichtbar + NetworkFeatures = Netzwerkfeatures + CoolnessPeriod = Abkühlzeit (Tage) + TieringPolicy = Tiering-Richtlinie + RetrievalPolicy = Abrufrichtlinie + VolumeType = Volumetyp + ProvisioningState = Bereitstellungsstatus + KerberosEnabled = Kerberos + LdapEnabled = LDAP + SmbEncryption = SMB-Verschlüsselung + SmbContinuouslyAvailable = SMB Continuously Available + SmbAccessBasedEnumeration = SMB ABE + FileSystemId = Dateisystem-ID + Domain = Domäne + Username = Benutzername + Site = AD-Standort + OrganizationalUnit = Organisationseinheit + SmbServerName = SMB-Servername + AesEncryption = AES-Verschlüsselung + LdapSigning = LDAP-Signierung + EncryptDCConnection = DC-Verbindung verschlüsseln + AllowLocalNfsUsersWithLdap = Lokale NFS-Benutzer mit LDAP zulassen + DnsServers = DNS-Server + Enabled = Aktiviert + HourlySchedule = Stündlicher Zeitplan + DailySchedule = Täglicher Zeitplan + WeeklySchedule = Wöchentlicher Zeitplan + MonthlySchedule = Monatlicher Zeitplan + SnapshotsToKeep = Aufzubewahrende Snapshots + Minute = Minute + Hour = Stunde + Day = Wochentag + DaysOfMonth = Tage des Monats + DailyBackups = Aufzubewahrende tägliche Sicherungen + WeeklyBackups = Aufzubewahrende wöchentliche Sicherungen + MonthlyBackups = Aufzubewahrende monatliche Sicherungen + RuleIndex = Regel + AllowedClients = Zulässige Clients + UnixReadWrite = NFS Lesen/Schreiben + UnixReadOnly = NFS Schreibgeschützt + Nfsv3 = NFSv3 + Nfsv41 = NFSv4.1 + HasRootAccess = Root-Zugriff + Kerberos5ReadWrite = Kerberos 5 R/W + Kerberos5iReadWrite = Kerberos 5i R/W + Kerberos5pReadWrite = Kerberos 5p R/W + ChownMode = Chown-Modus + IpAddress = IP-Adresse + SmbServerFqdn = SMB-Server-FQDN + Created = Erstellt + None = Keine + NoPolicy = Keine Richtlinie zugewiesen + NotConfigured = Nicht konfiguriert + InUse = In Verwendung + PlatformManaged = Plattformverwaltet + CustomerManaged = Kundenverwaltet + Yes = Yes + No = No +'@ + +# Azure Management Groups (Get-AbrAzManagementGroup) +GetAbrAzManagementGroup = ConvertFrom-StringData @' + InfoLevel = ManagementGroup InfoLevel auf {0} gesetzt. + Collecting = Sammlung von Azure Management Group-Informationen. + SectionInfo = Azure Management Groups stellen einen Governance-Bereich über Abonnements dar. Alle Abonnements innerhalb einer Verwaltungsgruppe erben automatisch die auf die Verwaltungsgruppe angewendeten Bedingungen, was eine konsistente Richtlinien- und Zugriffskontrolle über Ihre gesamte Azure-Landschaft ermöglicht. + Heading = Verwaltungsgruppen + TableHeading = Verwaltungsgruppen + DiagramHeading = Hierarchie der Verwaltungsgruppe + DiagramAltText = Hierarchiediagramm der Azure-Verwaltungsgruppe + DiagramError = Kann Hierarchiediagramm der Verwaltungsgruppe nicht generieren: {0}. + Name = Name + Id = Management Group ID + ParentName = Übergeordnete Gruppe + ChildGroupCount = Untergeordnete Gruppen + SubscriptionCount = Abonnements + ResourceGroup = Ressourcengruppe + Location = Standort + NotFound = Keine Verwaltungsgruppen gefunden. + None = Keine + ErrorMessage = Fehler beim Sammeln von Management Group-Informationen: +'@ + +# Azure Private DNS Zones (Get-AbrAzPrivateDnsZone) +GetAbrAzPrivateDnsZone = ConvertFrom-StringData @' + InfoLevel = PrivateDnsZone-InfoLevel auf {0} gesetzt. + Collecting = Azure Private DNS-Zoneninformationen werden gesammelt. + SectionInfo = Azure Private DNS-Zonen bieten einen zuverlässigen, sicheren DNS-Dienst zum Verwalten und Auflösen von Domänennamen in einem virtuellen Netzwerk, ohne eine benutzerdefinierte DNS-Lösung hinzufügen zu müssen. Private DNS-Zonen sind im öffentlichen Internet nicht sichtbar und ermöglichen die Verwendung eigener Domänennamen anstelle der von Azure bereitgestellten Namen. + ParagraphDetail = Die folgenden Abschnitte beschreiben die Konfiguration der privaten DNS-Zone(n) im Abonnement {0}. + ParagraphSummary = Die folgende Tabelle fasst die Konfiguration der privaten DNS-Zone(n) im Abonnement {0} zusammen. + Heading = Private DNS-Zonen + TableHeading = Private DNS-Zone + Name = Name + ResourceGroup = Ressourcengruppe + Location = Standort + Subscription = Abonnement + SubscriptionID = Abonnement-ID + RecordSets = Ressourceneintragssätze + MaxRecordSets = Max. Ressourceneintragssätze + VirtualNetworkLinks = VNET-Verknüpfungen + VNetLinksWithRegistration = VNET-Verknüpfungen mit automatischer Registrierung + ProvisioningState = Bereitstellungsstatus + LinkName = Verknüpfungsname + VirtualNetwork = Virtuelles Netzwerk + AutoRegistration = Automatische Registrierung + VirtualNetworkLinkState = Verknüpfungsstatus + Locks = Sperren + Tags = Tags + None = Keine + ErrorMessage = Fehler beim Sammeln von Private DNS-Zoneninformationen: +'@ + +# Azure Virtual Network Gateway (Get-AbrAzVirtualNetworkGateway) +GetAbrAzVirtualNetworkGateway = ConvertFrom-StringData @' + InfoLevel = VirtualNetworkGateway-InfoLevel auf {0} gesetzt. + Collecting = Azure Virtual Network Gateway-Informationen werden gesammelt. + SectionInfo = Azure Virtual Network Gateways verbinden Ihre lokalen Netzwerke über Site-to-Site-VPNs mit Azure und verbinden Azure-VNets über VNet-zu-VNet-VPNs miteinander. ExpressRoute-Gateways ermöglichen private, dedizierte Verbindungen zu Azure ohne Nutzung des öffentlichen Internets. + ParagraphDetail = Die folgenden Abschnitte beschreiben die Konfiguration der virtuellen Netzwerkgateways im Abonnement {0}. + ParagraphSummary = Die folgende Tabelle fasst die Konfiguration der virtuellen Netzwerkgateways im Abonnement {0} zusammen. + Heading = Virtuelle Netzwerkgateways + TableHeading = Virtuelles Netzwerkgateway + Name = Name + ResourceGroup = Ressourcengruppe + Location = Standort + Subscription = Abonnement + SubscriptionID = Abonnement-ID + VirtualNetwork = Virtuelles Netzwerk + GatewayType = Gatewaytyp + VpnType = VPN-Typ + SKU = SKU + Generation = Generation + ActiveActive = Aktiv-Aktiv + EnableBgp = BGP aktiviert + BgpAsn = BGP-ASN + BgpPeeringAddress = BGP-Peering-Adresse + ProvisioningState = Bereitstellungsstatus + Connections = Verbindungen + ConnectionName = Name + ConnectionType = Verbindungstyp + ConnectionStatus = Verbindungsstatus + ConnectionProtocol = Protokoll + RoutingWeight = Routinggewichtung + NotApplicable = N/V + Locks = Sperren + Tags = Tags + None = Keine + ErrorMessage = Fehler beim Sammeln von Virtual Network Gateway-Informationen: +'@ + +# Azure DDoS Protection Plan (Get-AbrAzDdosProtectionPlan) +GetAbrAzDdosProtectionPlan = ConvertFrom-StringData @' + InfoLevel = DDoSProtectionPlan-InfoLevel auf {0} gesetzt. + Collecting = Azure DDoS-Schutzplan-Informationen werden gesammelt. + SectionInfo = Azure DDoS-Schutzplaene bieten erweiterte DDoS-Abwehrfunktionen fuer alle Ressourcen in einem virtuellen Netzwerk. Sie bieten Telemetrie, Warnmeldungen und detaillierte Analysen zum Schutz Ihrer Azure-Ressourcen vor DDoS-Angriffen. + ParagraphDetail = Die folgenden Abschnitte beschreiben die Konfiguration der DDoS-Schutzplaene im Abonnement {0}. + ParagraphSummary = Die folgende Tabelle fasst die Konfiguration der DDoS-Schutzplaene im Abonnement {0} zusammen. + Heading = DDoS-Schutzplaene + TableHeading = DDoS-Schutzplan + Name = Name + ResourceGroup = Ressourcengruppe + Location = Standort + Subscription = Abonnement + SubscriptionID = Abonnement-ID + ProtectedVirtualNetworks = Geschuetzte virtuelle Netzwerke + VirtualNetworkName = Virtuelles Netzwerk + ProvisioningState = Bereitstellungsstatus + Locks = Sperren + Tags = Tags + None = Keine + ErrorMessage = Fehler beim Sammeln von DDoS-Schutzplan-Informationen: +'@ + +# Azure Application Gateway (Get-AbrAzApplicationGateway) +GetAbrAzApplicationGateway = ConvertFrom-StringData @' + InfoLevel = ApplicationGateway-InfoLevel auf {0} gesetzt. + Collecting = Azure Application Gateway-Informationen werden gesammelt. + SectionInfo = Azure Application Gateways sind Lastenausgleicher fuer Webdatenverkehr auf Layer 7. Sie unterstuetzen SSL/TLS-Terminierung, URL-basiertes Routing, Multi-Site-Hosting, Sitzungsaffinitaet und Web Application Firewall-Integration. + ParagraphDetail = Die folgenden Abschnitte beschreiben die Konfiguration der Application Gateways im Abonnement {0}. + ParagraphSummary = Die folgende Tabelle fasst die Konfiguration der Application Gateways im Abonnement {0} zusammen. + Heading = Application Gateways + TableHeading = Application Gateway + Name = Name + ResourceGroup = Ressourcengruppe + Location = Standort + Subscription = Abonnement + SubscriptionID = Abonnement-ID + VirtualNetwork = Virtuelles Netzwerk + Subnet = Subnetz + SKU = SKU + Tier = Stufe + Capacity = Kapazitaet + WafEnabled = WAF aktiviert + WafMode = WAF-Modus + Http2Enabled = HTTP/2 aktiviert + FrontendIPs = Frontend-IPs + OperationalState = Betriebsstatus + ProvisioningState = Bereitstellungsstatus + Listeners = HTTP-Listener + ListenerName = Listener + Protocol = Protokoll + Port = Port + HostName = Hostname + BackendPools = Backend-Adresspools + PoolName = Poolname + BackendTargets = Backend-Ziele + RoutingRules = Anforderungsroutingregeln + RuleName = Regelname + RuleType = Regeltyp + BackendPool = Backend-Pool + BackendHttpSettings = HTTP-Einstellungen + Unlimited = Unbegrenzt + NotApplicable = N/V + Tags = Tags + None = Keine + ErrorMessage = Fehler beim Sammeln von Application Gateway-Informationen: +'@ + +# Azure Data Collection Rules (Get-AbrAzDataCollectionRule) +GetAbrAzDataCollectionRule = ConvertFrom-StringData @' + InfoLevel = DataCollectionRule-InfoLevel auf {0} gesetzt. + Collecting = Azure Datensammlungsregel-Informationen werden gesammelt. + SectionInfo = Azure Datensammlungsregeln definieren, welche Ueberwachungsdaten gesammelt werden sollen, woher sie stammen und wohin sie gesendet werden. Sie legen Datenquellen wie Leistungsindikatoren, Windows-Ereignisprotokolle und Syslog fest und leiten diese Daten an Log Analytics-Arbeitsbereiche oder andere Ziele weiter. + ParagraphDetail = Die folgenden Abschnitte beschreiben die Konfiguration der Datensammlungsregeln im Abonnement {0}. + ParagraphSummary = Die folgende Tabelle fasst die Konfiguration der Datensammlungsregeln im Abonnement {0} zusammen. + Heading = Datensammlungsregeln + TableHeading = Datensammlungsregel + Name = Name + ResourceGroup = Ressourcengruppe + Location = Standort + Subscription = Abonnement + SubscriptionID = Abonnement-ID + Description = Beschreibung + DataSources = Datenquellen + LogAnalyticsDestinations = Log Analytics-Ziele + ProvisioningState = Bereitstellungsstatus + PerformanceCounters = Leistungsindikatoren + WindowsEventLogs = Windows-Ereignisprotokolle + Syslog = Syslog + Extensions = Erweiterungen + LogFiles = Protokolldateien + Destinations = Log Analytics-Ziele + DestinationName = Name + WorkspaceId = Arbeitsbereich-Ressourcen-ID + DataFlows = Datenfluesse + Streams = Datenstroeme + Tags = Tags + None = Keine + ErrorMessage = Fehler beim Sammeln von Datensammlungsregel-Informationen: +'@ + +# Azure Public IP Addresses (Get-AbrAzPublicIpAddress) +GetAbrAzPublicIpAddress = ConvertFrom-StringData @' + InfoLevel = PublicIpAddress-InfoLevel auf {0} gesetzt. + Collecting = Azure oeffentliche IP-Adressen-Informationen werden gesammelt. + SectionInfo = Azure oeffentliche IP-Adressen stellen internetseitige IP-Adressen fuer Ressourcen wie virtuelle Computer, Lastenausgleicher, VPN-Gateways und Application Gateways bereit. Sie unterstuetzen dynamische und statische Zuweisung und sind in den SKUs Basic und Standard verfuegbar. + ParagraphDetail = Die folgenden Abschnitte beschreiben die Konfiguration der oeffentlichen IP-Adressen im Abonnement {0}. + ParagraphSummary = Die folgende Tabelle fasst die Konfiguration der oeffentlichen IP-Adressen im Abonnement {0} zusammen. + Heading = Oeffentliche IP-Adressen + TableHeading = Oeffentliche IP-Adresse + Name = Name + ResourceGroup = Ressourcengruppe + Location = Standort + Subscription = Abonnement + SubscriptionID = Abonnement-ID + SKU = SKU + Tier = Stufe + IpVersion = IP-Version + AllocationMethod = Zuweisungsmethode + IpAddress = IP-Adresse + DnsLabel = DNS-Bezeichnung + Fqdn = FQDN + Zones = Verfuegbarkeitszonen + AssociatedResource = Zugeordnete Ressource + ProvisioningState = Bereitstellungsstatus + NotAssigned = Nicht zugewiesen + Tags = Tags + None = Keine + ErrorMessage = Fehler beim Sammeln von oeffentlichen IP-Adressen-Informationen: +'@ + +# Azure Network Watchers (Get-AbrAzNetworkWatcher) +GetAbrAzNetworkWatcher = ConvertFrom-StringData @' + InfoLevel = NetworkWatcher-InfoLevel auf {0} gesetzt. + Collecting = Azure Network Watcher-Informationen werden gesammelt. + SectionInfo = Azure Network Watcher bietet Netzwerkueberwachungs- und Diagnosefunktionen pro Region. NSG-Datenflussprotokolle erfassen Informationen ueber den IP-Datenverkehr durch Netzwerksicherheitsgruppen und koennen optional ueber Traffic Analytics an einen Log Analytics-Arbeitsbereich weitergeleitet werden. + ParagraphDetail = Die folgenden Abschnitte beschreiben die Konfiguration der Network Watcher im Abonnement {0}. + ParagraphSummary = Die folgende Tabelle fasst die Konfiguration der Network Watcher im Abonnement {0} zusammen. + Heading = Network Watcher + TableHeading = Network Watcher + Name = Name + ResourceGroup = Ressourcengruppe + Location = Standort + Subscription = Abonnement + SubscriptionID = Abonnement-ID + FlowLogs = Datenflussprotokolle + ProvisioningState = Bereitstellungsstatus + FlowLogsHeading = NSG-Datenflussprotokolle + FlowLogName = Name + TargetResource = Zielressource + FlowLogEnabled = Aktiviert + RetentionDays = Aufbewahrung (Tage) + TrafficAnalytics = Traffic Analytics + StorageAccount = Speicherkonto + Enabled = Aktiviert + Disabled = Deaktiviert + Unlimited = Unbegrenzt + Tags = Tags + None = Keine + ErrorMessage = Fehler beim Sammeln von Network Watcher-Informationen: +'@ + +# Azure VM Scale Sets (Get-AbrAzVmScaleSet) +GetAbrAzVmScaleSet = ConvertFrom-StringData @' + InfoLevel = VmScaleSet-InfoLevel auf {0} gesetzt. + Collecting = Azure Virtual Machine Scale Set-Informationen werden gesammelt. + SectionInfo = Azure Virtual Machine Scale Sets (VMSS) ermoeglichen die Bereitstellung und Verwaltung einer Gruppe identischer, lastverteilter virtueller Maschinen. Sie unterstuetzen automatische Skalierung, mehrere Verfuegbarkeitszonen und flexible oder einheitliche Orchestrierungsmodi. + ParagraphDetail = Die folgenden Abschnitte beschreiben die Konfiguration der VM-Skalierungsgruppen im Abonnement {0}. + ParagraphSummary = Die folgende Tabelle fasst die Konfiguration der VM-Skalierungsgruppen im Abonnement {0} zusammen. + Heading = VM-Skalierungsgruppen + TableHeading = VM-Skalierungsgruppe + Name = Name + ResourceGroup = Ressourcengruppe + Location = Standort + Subscription = Abonnement + SubscriptionID = Abonnement-ID + VmSize = VM-Groesse + Instances = Instanzen + OrchestrationMode = Orchestrierungsmodus + UpgradePolicy = Upgraderichtlinie + Overprovision = Ueberbereitstellung + SinglePlacementGroup = Einzelne Platzierungsgruppe + Zones = Verfuegbarkeitszonen + Identity = Identitaet + ProvisioningState = Bereitstellungsstatus + Tags = Tags + None = Keine + ErrorMessage = Fehler beim Sammeln von VM-Skalierungsgruppen-Informationen: +'@ + +# Azure Maintenance Configurations (Get-AbrAzMaintenanceConfiguration) +GetAbrAzMaintenanceConfiguration = ConvertFrom-StringData @' + InfoLevel = MaintenanceConfiguration-InfoLevel auf {0} gesetzt. + Collecting = Azure Wartungskonfigurationsinformationen werden gesammelt. + SectionInfo = Azure-Wartungskonfigurationen definieren geplante Wartungsfenster fuer Azure-Ressourcen. Sie steuern, wann Plattformupdates, BS-Patches und andere Wartungsaktivitaeten angewendet werden, um ungeplante Ausfallzeiten zu reduzieren. + ParagraphDetail = Die folgenden Abschnitte beschreiben die Konfiguration der Wartungskonfigurationen im Abonnement {0}. + ParagraphSummary = Die folgende Tabelle fasst die Konfiguration der Wartungskonfigurationen im Abonnement {0} zusammen. + Heading = Wartungskonfigurationen + TableHeading = Wartungskonfiguration + Name = Name + ResourceGroup = Ressourcengruppe + Location = Standort + Subscription = Abonnement + SubscriptionID = Abonnement-ID + Scope = Bereich + Visibility = Sichtbarkeit + StartDateTime = Startdatum/-uhrzeit + ExpirationDateTime = Ablaufdatum/-uhrzeit + Duration = Dauer + RecurEvery = Wiederholung + TimeZone = Zeitzone + NotConfigured = Nicht konfiguriert + NoExpiry = Kein Ablaufdatum + Tags = Tags + None = Keine + ErrorMessage = Fehler beim Sammeln von Wartungskonfigurationsinformationen: +'@ + +# Azure User Assigned Managed Identities (Get-AbrAzUserAssignedManagedIdentity) +GetAbrAzUserAssignedManagedIdentity = ConvertFrom-StringData @' + InfoLevel = UserAssignedManagedIdentity-InfoLevel auf {0} gesetzt. + Collecting = Azure Benutzerseitig zugewiesene verwaltete Identitaetsinformationen werden gesammelt. + SectionInfo = Benutzerseitig zugewiesene verwaltete Azure-Identitaeten sind eigenstaendige Azure-Ressourcen, die eine Azure AD-Identitaet fuer Dienste bereitstellen, die sich bei Ressourcen mit Azure Active Directory-Authentifizierungsunterstuetzung authentifizieren. Sie sind unabhaengig von Azure-Diensten oder -Ressourcen und koennen mehreren Ressourcen zugewiesen werden. + ParagraphDetail = Die folgenden Abschnitte beschreiben die Konfiguration der benutzerseitig zugewiesenen verwalteten Identitaet(en) im Abonnement {0}. + ParagraphSummary = Die folgende Tabelle fasst die Konfiguration der benutzerseitig zugewiesenen verwalteten Identitaet(en) im Abonnement {0} zusammen. + Heading = Benutzerseitig zugewiesene verwaltete Identitaeten + TableHeading = Benutzerseitig zugewiesene verwaltete Identitaet + Name = Name + ResourceGroup = Ressourcengruppe + Location = Standort + Subscription = Abonnement + SubscriptionID = Abonnement-ID + ClientID = Client-ID + PrincipalID = Prinzipal-ID + TenantID = Mandanten-ID + Tags = Tags + None = Keine + ErrorMessage = Fehler beim Sammeln von Informationen zu benutzerseitig zugewiesenen verwalteten Identitaeten: +'@ + +# Azure Automation Accounts (Get-AbrAzAutomationAccount) +GetAbrAzAutomationAccount = ConvertFrom-StringData @' + InfoLevel = AutomationAccount-InfoLevel auf {0} gesetzt. + Collecting = Azure Automation-Kontoinformationen werden gesammelt. + SectionInfo = Azure Automation-Konten bieten cloudbasierte Automatisierung und Konfigurationsverwaltung mit Unterstuetzung fuer Prozessautomatisierung ueber Runbooks, Konfigurationsverwaltung und Updateverwaltung fuer Azure- und lokale Umgebungen. + ParagraphDetail = Die folgenden Abschnitte beschreiben die Konfiguration der Automation-Konten im Abonnement {0}. + ParagraphSummary = Die folgende Tabelle fasst die Konfiguration der Automation-Konten im Abonnement {0} zusammen. + Heading = Automation-Konten + TableHeading = Automation-Konto + Name = Name + ResourceGroup = Ressourcengruppe + Location = Standort + Subscription = Abonnement + SubscriptionID = Abonnement-ID + State = Status + RunbooksHeading = Runbooks + RunbookType = Typ + LastModified = Zuletzt geaendert + VariablesHeading = Variablen + Encrypted = Verschluesselt + Description = Beschreibung + SchedulesHeading = Zeitplaene + Enabled = Aktiviert + Frequency = Haeufigkeit + NextRun = Naechste Ausfuehrung + CredentialsHeading = Anmeldeinformationen + UserName = Benutzername + Yes = Ja + No = Nein + Tags = Tags + None = Keine + ErrorMessage = Fehler beim Sammeln von Automation-Kontoinformationen: +'@ + +# Azure Diagnostic Settings (Get-AbrAzDiagnosticSetting) +GetAbrAzDiagnosticSetting = ConvertFrom-StringData @' + InfoLevel = DiagnosticSetting-InfoLevel auf {0} gesetzt. + Collecting = Azure Diagnoseeinstellungsinformationen werden gesammelt. + SectionInfo = Azure-Diagnoseeinstellungen konfigurieren den Export von Plattformprotokollen und Metriken aus Azure-Ressourcen an Ziele wie Log Analytics-Arbeitsbereiche, Speicherkonten und Event Hubs zur Ueberwachung, Pruefung und Analyse. + ParagraphDetail = Die folgenden Abschnitte beschreiben die Konfiguration der Diagnoseeinstellungen im Abonnement {0}. + ParagraphSummary = Die folgende Tabelle fasst die Konfiguration der Diagnoseeinstellungen im Abonnement {0} zusammen. + Heading = Diagnoseeinstellungen + TableHeading = Diagnoseeinstellung + ResourceName = Ressourcenname + ResourceType = Ressourcentyp + ResourceGroup = Ressourcengruppe + Name = Name + Location = Standort + Subscription = Abonnement + SubscriptionID = Abonnement-ID + LogAnalyticsWorkspace = Log Analytics-Arbeitsbereich + StorageAccount = Speicherkonto + EventHub = Event Hub + LogCategoriesEnabled = Protokollkategorien (aktiviert) + MetricsEnabled = Metriken aktiviert + Yes = Ja + No = Nein + None = Keine + ErrorMessage = Fehler beim Sammeln von Diagnoseeinstellungsinformationen: +'@ + +# Azure DNS Forwarding Rulesets (Get-AbrAzDnsForwardingRuleset) +GetAbrAzDnsForwardingRuleset = ConvertFrom-StringData @' + InfoLevel = DnsForwardingRuleset-InfoLevel auf {0} gesetzt. + Collecting = Azure DNS-Weiterleitungsregelsatz-Informationen werden gesammelt. + SectionInfo = Azure DNS-Weiterleitungsregelsaetze definieren Saetze bedingter Weiterleitungsregeln, die DNS-Abfragen an bestimmte DNS-Server weiterleiten. Sie sind mit ausgehenden Endpunkten des DNS Private Resolvers verbunden und mit virtuellen Netzwerken verknuepft, um das DNS-Aufloesungsverhalten zu steuern. + ParagraphDetail = Die folgenden Abschnitte beschreiben die Konfiguration der DNS-Weiterleitungsregelsaetze im Abonnement {0}. + ParagraphSummary = Die folgende Tabelle fasst die Konfiguration der DNS-Weiterleitungsregelsaetze im Abonnement {0} zusammen. + Heading = DNS-Weiterleitungsregelsaetze + TableHeading = DNS-Weiterleitungsregelsatz + Name = Name + ResourceGroup = Ressourcengruppe + Location = Standort + Subscription = Abonnement + SubscriptionID = Abonnement-ID + ForwardingRules = Weiterleitungsregeln + VirtualNetworkLinks = VNET-Verbindungen + OutboundEndpoints = Ausgehende Endpunkte + ProvisioningState = Bereitstellungsstatus + ForwardingRulesHeading = Weiterleitungsregeln + RuleName = Name + DomainName = Domaenname + TargetServers = Ziel-DNS-Server + RuleState = Status + VNetLinksHeading = VNET-Verbindungen + LinkName = Name + VirtualNetwork = Virtuelles Netzwerk + Tags = Tags + None = Keine + ErrorMessage = Fehler beim Sammeln von DNS-Weiterleitungsregelsatz-Informationen: +'@ + +# Azure Network Virtual Appliance (Get-AbrAzNetworkVirtualAppliance) +GetAbrAzNetworkVirtualAppliance = ConvertFrom-StringData @' + InfoLevel = NetworkVirtualAppliance-InfoLevel auf {0} gesetzt. + Collecting = Azure-Netzwerk-Virtual-Appliance-Informationen werden gesammelt. + Processing = Verarbeitung der Azure-Netzwerk-Virtual-Appliance '{0}'. + SectionInfo = Netzwerk-Virtual-Appliances (NVAs) sind Netzwerk- und Sicherheitsprodukte von Drittanbietern, die als virtuelle Maschinen in Azure bereitgestellt werden. Zu den gaengigen NVA-Workloads zaehlen Firewalls der naechsten Generation, SD-WAN-Gateways, WAN-Optimierer und Anwendungsbereitstellungscontroller. NVAs werden anhand ihres Azure-Marketplace-Imageherausgebers und optional anhand eines Ressourcen-Tags identifiziert. Benutzerdefinierte Routen (UDRs) mit dem naechsten Hop-Typ Virtual Appliance werden abgeglichen, um zu zeigen, welche Datenverkehrsfluesse durch jede NVA geleitet werden. + ParagraphSummary = Die folgende Tabelle fasst die im Abonnement {0} identifizierten Netzwerk-Virtual-Appliances zusammen. + ParagraphDetail = Die folgenden Abschnitte beschreiben die Konfiguration der im Abonnement {0} identifizierten Netzwerk-Virtual-Appliances. + Heading = Netzwerk-Virtual-Appliances + TableHeading = Netzwerk-Virtual-Appliance + TableHeadings = Netzwerk-Virtual-Appliances + Name = Name + ResourceGroup = Ressourcengruppe + Location = Standort + Subscription = Abonnement + SubscriptionID = Abonnement-ID + Vendor = Anbieter + Publisher = Herausgeber + Offer = Angebot + Sku = SKU + ImageVersion = Imageversion + Status = Status + Running = Wird ausgefuehrt + Deallocated = Freigegeben + Size = VM-Groesse + PrivateIPAddress = Private IP-Adresse + VirtualNetworkSubnet = Virtuelles Netzwerk / Subnetz + NetworkInterfaces = Netzwerkschnittstellen + DetectedBy = Erkannt durch + DetectedByPublisher = Marketplace-Herausgeber + DetectedByTag = Ressourcen-Tag + DetectedBoth = Marketplace-Herausgeber und Ressourcen-Tag + TagIdentified = Per Tag identifizierte NVA + AssociatedRoutes = Zugehoerige UDR-Routen + NoAssociatedRoutes = Es wurden keine UDR-Routen mit dem naechsten Hop-Typ Virtual Appliance gefunden, die auf diese NVA verweisen. + RouteTable = Routentabelle + RouteName = Routenname + AddressPrefix = Adresspraefix + NextHopIpAddress = Naechste Hop-IP-Adresse + Tags = Tags + None = Keine +'@ + } diff --git a/AsBuiltReport.Microsoft.Azure/Language/en-GB/MicrosoftAzure.psd1 b/AsBuiltReport.Microsoft.Azure/Language/en-GB/MicrosoftAzure.psd1 index 67b0a1f..1bdb0ef 100644 --- a/AsBuiltReport.Microsoft.Azure/Language/en-GB/MicrosoftAzure.psd1 +++ b/AsBuiltReport.Microsoft.Azure/Language/en-GB/MicrosoftAzure.psd1 @@ -11,6 +11,7 @@ InvokeAsBuiltReportMicrosoftAzure = ConvertFrom-StringData @' InfoLevelNotFound = InfoLevel for '{0}' not found. FunctionNotFound = Function '{0}' for section '{1}' not found. SectionError = Error processing section '{0}': {1}" + AzureApiError = Azure API call failed: {0} TenantNotFound = Azure Tenant '{0}' not found. TokenAccountIdRequired = Azure token authentication requires AccountId parameter. Use {0} with {1} @{{AccountId="user@domain.com"}}. ConnectingWithToken = Connecting to Azure using token for account {0} in tenant {1}. @@ -288,7 +289,7 @@ GetAbrAsrProtectedItems = ConvertFrom-StringData @' InfoLevel = SiteRecovery InfoLevel set at {0}. Collecting = Collecting Azure Site Recovery information '{0}'. CollectingItems = Collecting Azure Site Recovery Protected Items information. - ParagraghSummary = The following tables provides information for the Azure Site Recovery protected items within the {0} subscription. + ParagraphSummary = The following table provides information for the Azure Site Recovery protected items within the {0} subscription. Heading = Protected Items TableHeading = Protected Items SubHeading = Site Recovery @@ -301,6 +302,69 @@ GetAbrAsrProtectedItems = ConvertFrom-StringData @' ActiveLocation = Active Location TargetLocation = Target Location FailoverHealth = Failover Health + NoTestFailover = No test failover has been performed + ParagraphDetail = The following sections detail the configuration of the Azure Site Recovery protected items within the {0} subscription. + ReplicationProvider = Replication Provider + Rpo = RPO (mins) + LastRpoCalculated = Last RPO Calculated + LastHeartbeat = Last Heartbeat + RecoveryVmSize = Recovery VM Size + RecoveryAvailabilityZone = Recovery Availability Zone + NotAvailable = N/A + None = None +'@ + +# Azure Site Recovery Replication Policies (Get-AbrAzAsrPolicy) +GetAbrAzAsrPolicy = ConvertFrom-StringData @' + InfoLevel = AsrPolicy InfoLevel set at {0}. + Collecting = Collecting Azure Site Recovery Policy information for '{0}'. + SectionInfo = Azure Site Recovery replication policies define recovery point objectives (RPO) and recovery point history for replicated virtual machines. + Heading = Replication Policies + TableHeadings = Replication Policies + ParagraphSummary = The following table summarises the Azure Site Recovery replication policies configured for the {0} recovery services vault. + ParagraphDetail = The following sections detail the Azure Site Recovery replication policies configured for the {0} recovery services vault. + Name = Name + Provider = Provider + RpoThreshold = RPO Threshold (mins) + RecoveryPointHistory = Recovery Point History (hrs) + AppConsistentFrequency = App-Consistent Snapshot (mins) + CrashConsistentFrequency = Crash-Consistent Snapshot (mins) + MultiVmSync = Multi-VM Sync + NotApplicable = N/A +'@ + +# Azure Site Recovery Recovery Plans (Get-AbrAzAsrRecoveryPlan) +GetAbrAzAsrRecoveryPlan = ConvertFrom-StringData @' + InfoLevel = AsrRecoveryPlan InfoLevel set at {0}. + Collecting = Collecting Azure Site Recovery Recovery Plan information for '{0}'. + SectionInfo = Azure Site Recovery recovery plans orchestrate the failover and recovery of groups of virtual machines, enabling coordinated DR operations. + Heading = Recovery Plans + TableHeadings = Recovery Plans + ParagraphSummary = The following table summarises the Azure Site Recovery recovery plans configured for the {0} recovery services vault. + ParagraphDetail = The following sections detail the Azure Site Recovery recovery plans configured for the {0} recovery services vault. + Name = Name + PrimaryFabric = Primary Location + RecoveryFabric = Recovery Location + GroupCount = Groups + ProtectedItemCount = Protected Items + FailoverDeploymentModel = Failover Deployment Model + None = None +'@ + +# Azure Site Recovery Network Mappings (Get-AbrAzAsrNetworkMapping) +GetAbrAzAsrNetworkMapping = ConvertFrom-StringData @' + InfoLevel = AsrNetworkMapping InfoLevel set at {0}. + Collecting = Collecting Azure Site Recovery Network Mapping information for '{0}'. + SectionInfo = Azure Site Recovery network mappings define the relationship between source and target virtual networks used during failover operations. + Heading = Network Mappings + TableHeadings = Network Mappings + ParagraphSummary = The following table summarises the Azure Site Recovery network mappings configured for the {0} recovery services vault. + ParagraphDetail = The following sections detail the Azure Site Recovery network mappings configured for the {0} recovery services vault. + Name = Name + PrimaryNetwork = Primary Network + RecoveryNetwork = Recovery Network + MappingState = Mapping State + None = None '@ # Azure Availability Sets (Get-AbrAzAvailabilitySet) @@ -422,6 +486,7 @@ GetAbrAzStorageAccount = ConvertFrom-StringData @' Disabled = Disabled Unknown = Unknown Created = Created + Locks = Locks Tags = Tags None = None '@ @@ -484,6 +549,7 @@ GetAbrAzFirewall = ConvertFrom-StringData @' NatRules = NAT Rules NetworkRules = Network Rules AppRules = Application Rules + Locks = Locks Tags = Tags None = None '@ @@ -592,6 +658,7 @@ GetAbrAzKeyVault = ConvertFrom-StringData @' Disabled = Disabled NoAccessEnabled = No access enabled EnabledDays = Enabled ({0} days) + Locks = Locks Tags = Tags None = None days = days @@ -665,7 +732,7 @@ GetAbrAzLoadBalancer = ConvertFrom-StringData @' Heading = Load Balancers TableHeading = Load Balancer TableHeadings = Load Balancers - LoadBalancerImage = Load Balancer Image + Image = Load Balancer Image ImageError = Unable to display Load Balancer image Name = Name ResourceGroup = Resource Group @@ -715,6 +782,7 @@ GetAbrAzLogAnalyticsWorkspace = ConvertFrom-StringData @' Disabled = Disabled Unknown = Unknown NoQuota = No Quota Set + Locks = Locks Tags = Tags None = None '@ @@ -859,6 +927,13 @@ GetAbrAzRecoveryServicesVault = ConvertFrom-StringData @' ProvisioningState = Provisioning State PrivateEndpointStateForBackup = Private Endpoint State for Backup PrivateEndpointStateForSiteRecovery = Private Endpoint State for Site Recovery + StorageRedundancy = Storage Redundancy + CrossRegionRestore = Cross Region Restore + SoftDeleteState = Soft Delete State + SoftDeleteRetentionDays = Soft Delete Retention (Days) + ImmutabilityState = Immutability State + PublicNetworkAccess = Public Network Access + Locks = Locks Tags = Tags None = None '@ @@ -883,6 +958,7 @@ GetAbrAzRouteTable = ConvertFrom-StringData @' AddressPrefix = Address Prefix NextHopType = Next Hop Type NextHopIpAddress = Next Hop IP Address + Locks = Locks Tags = Tags None = None '@ @@ -1063,6 +1139,7 @@ GetAbrAzVirtualNetwork = ConvertFrom-StringData @' Subnets = Subnets DnsServers = DNS Servers Default = Default (Azure-provided) + Locks = Locks Tags = Tags None = None '@ @@ -1254,4 +1331,588 @@ GetAbrAzDesktopVirtualization = ConvertFrom-StringData @' Allowed = Allowed '@ + +# Azure NetApp Files (Get-AbrAzNetAppFiles) +GetAbrAzNetAppFiles = ConvertFrom-StringData @' + InfoLevel = NetAppFiles InfoLevel set at {0}. + Collecting = Collecting Azure NetApp Files information. + SectionInfo = Azure NetApp Files is an enterprise-class, high-performance, metered file storage service running on Azure. It supports SMB, NFSv3, NFSv4.1, and dual-protocol volumes with integrated snapshots, cross-region replication, and backup. + AccountsSummary = The following table summarises the NetApp Files accounts within the {0} subscription. + PoolsSummary = The following table summarises the capacity pools within the {0} subscription. + VolumesSummary = The following table summarises the volumes within the {0} subscription. + SnapshotPoliciesSummary = The following table summarises the snapshot policies within the {0} subscription. + BackupPoliciesSummary = The following table summarises the backup policies within the {0} subscription. + AdConfigIntro = Active Directory configuration for NetApp account '{0}'. + MountTargetsIntro = Mount targets for volume '{0}'. + WarningPoolAllocation = WARNING: Capacity pool '{0}' is {1}% allocated ({2} GiB of {3} GiB). + WarningAdStatus = WARNING: Active Directory configuration for account '{0}' has status '{1}'. + Heading = Azure NetApp Files + AccountsHeading = NetApp Accounts + PoolsHeading = Capacity Pools + VolumesHeading = Volumes + SnapshotPoliciesHeading = Snapshot Policies + BackupPoliciesHeading = Backup Policies + ActiveDirectoryHeading = Active Directory Configuration + EncryptionHeading = Encryption Configuration + ExportPolicyHeading = Export Policy Rules + MountTargetsHeading = Mount Targets + DataProtectionHeading = Data Protection + SnapshotsHeading = Snapshots + QuotaRulesHeading = Volume Quota Rules + Name = Name + ResourceGroup = Resource Group + Location = Location + Tags = Tags + Status = Status + Type = Type + Account = Account + Pool = Pool + Volume = Volume + ServiceLevel = Service Level + QosType = QoS Type + SizeTiB = Size (TiB) + SizeGiB = Size (GiB) + QuotaGiB = Quota (GiB) + AllocatedGiB = Allocated (GiB) + PercentAllocated = % Allocated + VolumeCount = Volumes + TotalThroughput = Total Throughput (MiB/s) + UtilizedThroughput = Utilised Throughput (MiB/s) + CoolAccess = Cool Access + EncryptionType = Encryption Type + EncryptionKeySource = Encryption Key Source + EncryptionKeyVault = Key Vault URI + EncryptionKeyName = Key Name + Protocol = Protocol + Subnet = Delegated Subnet + Zone = Availability Zone + Throughput = Throughput (MiB/s) + ActualThroughput = Actual Throughput (MiB/s) + SecurityStyle = Security Style + UnixPermission = Unix Permissions + SnapshotPolicy = Snapshot Policy + BackupPolicy = Backup Policy + SnapshotDirVisible = Snapshot Dir Visible + NetworkFeatures = Network Features + CoolnessPeriod = Coolness Period (days) + TieringPolicy = Tiering Policy + RetrievalPolicy = Retrieval Policy + VolumeType = Volume Type + ProvisioningState = Provisioning State + KerberosEnabled = Kerberos + LdapEnabled = LDAP + SmbEncryption = SMB Encryption + SmbContinuouslyAvailable = SMB Continuously Available + SmbAccessBasedEnumeration = SMB ABE + FileSystemId = File System ID + Domain = Domain + Username = Username + Site = AD Site + OrganizationalUnit = Organisational Unit + SmbServerName = SMB Server Name + AesEncryption = AES Encryption + LdapSigning = LDAP Signing + EncryptDCConnection = Encrypt DC Connection + AllowLocalNfsUsersWithLdap = Allow Local NFS Users with LDAP + DnsServers = DNS Servers + Enabled = Enabled + HourlySchedule = Hourly Schedule + DailySchedule = Daily Schedule + WeeklySchedule = Weekly Schedule + MonthlySchedule = Monthly Schedule + SnapshotsToKeep = Snapshots to Keep + Minute = Minute + Hour = Hour + Day = Day of Week + DaysOfMonth = Days of Month + DailyBackups = Daily Backups to Keep + WeeklyBackups = Weekly Backups to Keep + MonthlyBackups = Monthly Backups to Keep + RuleIndex = Rule + AllowedClients = Allowed Clients + UnixReadWrite = NFS Read/Write + UnixReadOnly = NFS Read-Only + Nfsv3 = NFSv3 + Nfsv41 = NFSv4.1 + HasRootAccess = Root Access + Kerberos5ReadWrite = Kerberos 5 R/W + Kerberos5iReadWrite = Kerberos 5i R/W + Kerberos5pReadWrite = Kerberos 5p R/W + ChownMode = Chown Mode + IpAddress = IP Address + SmbServerFqdn = SMB Server FQDN + Created = Created + None = None + NoPolicy = No Policy Attached + NotConfigured = Not Configured + InUse = InUse + PlatformManaged = Platform-Managed + CustomerManaged = Customer-Managed + Yes = Yes + No = No +'@ + +# Azure Management Groups (Get-AbrAzManagementGroup) +GetAbrAzManagementGroup = ConvertFrom-StringData @' + InfoLevel = ManagementGroup InfoLevel set at {0}. + Collecting = Collecting Azure Management Group information. + SectionInfo = Azure Management Groups provide a governance scope above subscriptions. All subscriptions within a management group automatically inherit the conditions applied to the management group, enabling consistent policy and access control across your entire Azure estate. + Heading = Management Groups + TableHeading = Management Groups + DiagramHeading = Management Group Hierarchy + DiagramAltText = Azure management group hierarchy diagram + DiagramError = Unable to generate Management Group hierarchy diagram: {0}. + Name = Name + Id = Management Group ID + ParentName = Parent Group + ChildGroupCount = Child Groups + SubscriptionCount = Subscriptions + ResourceGroup = Resource Group + Location = Location + NotFound = No Management Groups found. + None = None + ErrorMessage = Unable to collect Management Group information: +'@ + +# Azure Private DNS Zones (Get-AbrAzPrivateDnsZone) +GetAbrAzPrivateDnsZone = ConvertFrom-StringData @' + InfoLevel = PrivateDnsZone InfoLevel set at {0}. + Collecting = Collecting Azure Private DNS Zone information. + SectionInfo = Azure Private DNS Zones provide a reliable, secure DNS service to manage and resolve domain names in a virtual network without the need to add a custom DNS solution. Private DNS zones are not visible on the public internet and allow you to use your own custom domain names rather than the Azure-provided names. + ParagraphDetail = The following sections detail the configuration of the private DNS zone(s) within the {0} subscription. + ParagraphSummary = The following table summarises the configuration of the private DNS zone(s) within the {0} subscription. + Heading = Private DNS Zones + TableHeading = Private DNS Zone + Name = Name + ResourceGroup = Resource Group + Location = Location + Subscription = Subscription + SubscriptionID = Subscription ID + RecordSets = Record Sets + MaxRecordSets = Max Record Sets + VirtualNetworkLinks = Virtual Network Links + VNetLinksWithRegistration = VNet Links with Auto Registration + ProvisioningState = Provisioning State + LinkName = Link Name + VirtualNetwork = Virtual Network + AutoRegistration = Auto Registration + VirtualNetworkLinkState = Link State + Locks = Locks + Tags = Tags + None = None + ErrorMessage = Unable to collect Private DNS Zone information: +'@ + +# Azure Virtual Network Gateway (Get-AbrAzVirtualNetworkGateway) +GetAbrAzVirtualNetworkGateway = ConvertFrom-StringData @' + InfoLevel = VirtualNetworkGateway InfoLevel set at {0}. + Collecting = Collecting Azure Virtual Network Gateway information. + SectionInfo = Azure Virtual Network Gateways connect your on-premises networks to Azure through Site-to-Site VPNs, and connect Azure virtual networks to each other through VNet-to-VNet VPNs. ExpressRoute gateways enable private, dedicated connections to Azure without traversing the public internet. + ParagraphDetail = The following sections detail the configuration of the virtual network gateway(s) within the {0} subscription. + ParagraphSummary = The following table summarises the configuration of the virtual network gateway(s) within the {0} subscription. + Heading = Virtual Network Gateways + TableHeading = Virtual Network Gateway + Name = Name + ResourceGroup = Resource Group + Location = Location + Subscription = Subscription + SubscriptionID = Subscription ID + VirtualNetwork = Virtual Network + GatewayType = Gateway Type + VpnType = VPN Type + SKU = SKU + Generation = Generation + ActiveActive = Active-Active + EnableBgp = BGP Enabled + BgpAsn = BGP ASN + BgpPeeringAddress = BGP Peering Address + ProvisioningState = Provisioning State + Connections = Connections + ConnectionName = Name + ConnectionType = Connection Type + ConnectionStatus = Connection Status + ConnectionProtocol = Protocol + RoutingWeight = Routing Weight + NotApplicable = N/A + Locks = Locks + Tags = Tags + None = None + ErrorMessage = Unable to collect Virtual Network Gateway information: +'@ + +# Azure DDoS Protection Plan (Get-AbrAzDdosProtectionPlan) +GetAbrAzDdosProtectionPlan = ConvertFrom-StringData @' + InfoLevel = DDoSProtectionPlan InfoLevel set at {0}. + Collecting = Collecting Azure DDoS Protection Plan information. + SectionInfo = Azure DDoS Protection Plans provide enhanced DDoS mitigation capabilities for all resources in a virtual network. They offer telemetry, alerting, and detailed analytics to help protect your Azure resources against DDoS attacks. + ParagraphDetail = The following sections detail the configuration of the DDoS Protection Plan(s) within the {0} subscription. + ParagraphSummary = The following table summarises the configuration of the DDoS Protection Plan(s) within the {0} subscription. + Heading = DDoS Protection Plans + TableHeading = DDoS Protection Plan + Name = Name + ResourceGroup = Resource Group + Location = Location + Subscription = Subscription + SubscriptionID = Subscription ID + ProtectedVirtualNetworks = Protected Virtual Networks + VirtualNetworkName = Virtual Network + ProvisioningState = Provisioning State + Locks = Locks + Tags = Tags + None = None + ErrorMessage = Unable to collect DDoS Protection Plan information: +'@ + +# Azure Application Gateway (Get-AbrAzApplicationGateway) +GetAbrAzApplicationGateway = ConvertFrom-StringData @' + InfoLevel = ApplicationGateway InfoLevel set at {0}. + Collecting = Collecting Azure Application Gateway information. + SectionInfo = Azure Application Gateways are web traffic load balancers that operate at Layer 7. They support features such as SSL/TLS termination, URL-based routing, multi-site hosting, session affinity, and Web Application Firewall integration. + ParagraphDetail = The following sections detail the configuration of the application gateway(s) within the {0} subscription. + ParagraphSummary = The following table summarises the configuration of the application gateway(s) within the {0} subscription. + Heading = Application Gateways + TableHeading = Application Gateway + Name = Name + ResourceGroup = Resource Group + Location = Location + Subscription = Subscription + SubscriptionID = Subscription ID + VirtualNetwork = Virtual Network + Subnet = Subnet + SKU = SKU + Tier = Tier + Capacity = Capacity + WafEnabled = WAF Enabled + WafMode = WAF Mode + Http2Enabled = HTTP/2 Enabled + FrontendIPs = Frontend IPs + OperationalState = Operational State + ProvisioningState = Provisioning State + Listeners = HTTP Listeners + ListenerName = Listener + Protocol = Protocol + Port = Port + HostName = Host Name + BackendPools = Backend Address Pools + PoolName = Pool Name + BackendTargets = Backend Targets + RoutingRules = Request Routing Rules + RuleName = Rule Name + RuleType = Rule Type + BackendPool = Backend Pool + BackendHttpSettings = HTTP Settings + Unlimited = Unlimited + NotApplicable = N/A + Tags = Tags + None = None + ErrorMessage = Unable to collect Application Gateway information: +'@ + +# Azure Data Collection Rules (Get-AbrAzDataCollectionRule) +GetAbrAzDataCollectionRule = ConvertFrom-StringData @' + InfoLevel = DataCollectionRule InfoLevel set at {0}. + Collecting = Collecting Azure Data Collection Rule information. + SectionInfo = Azure Data Collection Rules define what monitoring data to collect, from where, and where to send it. They specify data sources such as performance counters, Windows event logs, and Syslog, and route that data to Log Analytics workspaces or other destinations. + ParagraphDetail = The following sections detail the configuration of the data collection rule(s) within the {0} subscription. + ParagraphSummary = The following table summarises the configuration of the data collection rule(s) within the {0} subscription. + Heading = Data Collection Rules + TableHeading = Data Collection Rule + Name = Name + ResourceGroup = Resource Group + Location = Location + Subscription = Subscription + SubscriptionID = Subscription ID + Description = Description + DataSources = Data Sources + LogAnalyticsDestinations = Log Analytics Destinations + ProvisioningState = Provisioning State + PerformanceCounters = Performance Counters + WindowsEventLogs = Windows Event Logs + Syslog = Syslog + Extensions = Extensions + LogFiles = Log Files + Destinations = Log Analytics Destinations + DestinationName = Name + WorkspaceId = Workspace Resource ID + DataFlows = Data Flows + Streams = Streams + Tags = Tags + None = None + ErrorMessage = Unable to collect Data Collection Rule information: +'@ + +# Azure Public IP Addresses (Get-AbrAzPublicIpAddress) +GetAbrAzPublicIpAddress = ConvertFrom-StringData @' + InfoLevel = PublicIpAddress InfoLevel set at {0}. + Collecting = Collecting Azure Public IP Address information. + SectionInfo = Azure Public IP Addresses provide internet-facing IP addresses for resources such as virtual machines, load balancers, VPN gateways, and application gateways. They support both dynamic and static allocation and are available in Basic and Standard SKUs. + ParagraphDetail = The following sections detail the configuration of the public IP address(es) within the {0} subscription. + ParagraphSummary = The following table summarises the configuration of the public IP address(es) within the {0} subscription. + Heading = Public IP Addresses + TableHeading = Public IP Address + Name = Name + ResourceGroup = Resource Group + Location = Location + Subscription = Subscription + SubscriptionID = Subscription ID + SKU = SKU + Tier = Tier + IpVersion = IP Version + AllocationMethod = Allocation Method + IpAddress = IP Address + DnsLabel = DNS Label + Fqdn = FQDN + Zones = Availability Zones + AssociatedResource = Associated Resource + ProvisioningState = Provisioning State + NotAssigned = Not Assigned + Tags = Tags + None = None + ErrorMessage = Unable to collect Public IP Address information: +'@ + +# Azure Network Watchers (Get-AbrAzNetworkWatcher) +GetAbrAzNetworkWatcher = ConvertFrom-StringData @' + InfoLevel = NetworkWatcher InfoLevel set at {0}. + Collecting = Collecting Azure Network Watcher information. + SectionInfo = Azure Network Watcher provides network monitoring and diagnostic capabilities per region. NSG Flow Logs capture information about IP traffic flowing through Network Security Groups and can optionally route data to a Log Analytics workspace via Traffic Analytics. + ParagraphDetail = The following sections detail the configuration of the network watcher(s) within the {0} subscription. + ParagraphSummary = The following table summarises the configuration of the network watcher(s) within the {0} subscription. + Heading = Network Watchers + TableHeading = Network Watcher + Name = Name + ResourceGroup = Resource Group + Location = Location + Subscription = Subscription + SubscriptionID = Subscription ID + FlowLogs = Flow Logs + ProvisioningState = Provisioning State + FlowLogsHeading = NSG Flow Logs + FlowLogName = Name + TargetResource = Target Resource + FlowLogEnabled = Enabled + RetentionDays = Retention (Days) + TrafficAnalytics = Traffic Analytics + StorageAccount = Storage Account + Enabled = Enabled + Disabled = Disabled + Unlimited = Unlimited + Tags = Tags + None = None + ErrorMessage = Unable to collect Network Watcher information: +'@ + +# Azure VM Scale Sets (Get-AbrAzVmScaleSet) +GetAbrAzVmScaleSet = ConvertFrom-StringData @' + InfoLevel = VmScaleSet InfoLevel set at {0}. + Collecting = Collecting Azure Virtual Machine Scale Set information. + SectionInfo = Azure Virtual Machine Scale Sets (VMSS) enable deployment and management of a group of identical, load-balanced virtual machines. They support autoscaling, multiple availability zones, and flexible or uniform orchestration modes. + ParagraphDetail = The following sections detail the configuration of the virtual machine scale set(s) within the {0} subscription. + ParagraphSummary = The following table summarises the configuration of the virtual machine scale set(s) within the {0} subscription. + Heading = VM Scale Sets + TableHeading = VM Scale Set + Name = Name + ResourceGroup = Resource Group + Location = Location + Subscription = Subscription + SubscriptionID = Subscription ID + VmSize = VM Size + Instances = Instances + OrchestrationMode = Orchestration Mode + UpgradePolicy = Upgrade Policy + Overprovision = Overprovision + SinglePlacementGroup = Single Placement Group + Zones = Availability Zones + Identity = Identity + ProvisioningState = Provisioning State + Tags = Tags + None = None + ErrorMessage = Unable to collect Virtual Machine Scale Set information: +'@ + +# Azure Maintenance Configurations (Get-AbrAzMaintenanceConfiguration) +GetAbrAzMaintenanceConfiguration = ConvertFrom-StringData @' + InfoLevel = MaintenanceConfiguration InfoLevel set at {0}. + Collecting = Collecting Azure Maintenance Configuration information. + SectionInfo = Azure Maintenance Configurations define scheduled maintenance windows for Azure resources. They control when platform updates, OS patching, and other maintenance activities are applied, reducing unplanned downtime. + ParagraphDetail = The following sections detail the configuration of the maintenance configuration(s) within the {0} subscription. + ParagraphSummary = The following table summarises the configuration of the maintenance configuration(s) within the {0} subscription. + Heading = Maintenance Configurations + TableHeading = Maintenance Configuration + Name = Name + ResourceGroup = Resource Group + Location = Location + Subscription = Subscription + SubscriptionID = Subscription ID + Scope = Scope + Visibility = Visibility + StartDateTime = Start Date/Time + ExpirationDateTime = Expiration Date/Time + Duration = Duration + RecurEvery = Recurrence + TimeZone = Time Zone + NotConfigured = Not Configured + NoExpiry = No Expiry + Tags = Tags + None = None + ErrorMessage = Unable to collect Maintenance Configuration information: +'@ + +# Azure User Assigned Managed Identities (Get-AbrAzUserAssignedManagedIdentity) +GetAbrAzUserAssignedManagedIdentity = ConvertFrom-StringData @' + InfoLevel = UserAssignedManagedIdentity InfoLevel set at {0}. + Collecting = Collecting Azure User Assigned Managed Identity information. + SectionInfo = Azure User Assigned Managed Identities are standalone Azure resources that provide an Azure AD identity for services to use when authenticating to resources that support Azure Active Directory authentication. They exist independently of any Azure service or resource and can be assigned to multiple resources. + ParagraphDetail = The following sections detail the configuration of the user assigned managed identity/identities within the {0} subscription. + ParagraphSummary = The following table summarises the configuration of the user assigned managed identity/identities within the {0} subscription. + Heading = User Assigned Managed Identities + TableHeading = User Assigned Managed Identity + Name = Name + ResourceGroup = Resource Group + Location = Location + Subscription = Subscription + SubscriptionID = Subscription ID + ClientID = Client ID + PrincipalID = Principal ID + TenantID = Tenant ID + Tags = Tags + None = None + ErrorMessage = Unable to collect User Assigned Managed Identity information: +'@ + +# Azure Automation Accounts (Get-AbrAzAutomationAccount) +GetAbrAzAutomationAccount = ConvertFrom-StringData @' + InfoLevel = AutomationAccount InfoLevel set at {0}. + Collecting = Collecting Azure Automation Account information. + SectionInfo = Azure Automation Accounts provide cloud-based automation and configuration management, supporting process automation via runbooks, configuration management, and update management across Azure and on-premises environments. + ParagraphDetail = The following sections detail the configuration of the automation account(s) within the {0} subscription. + ParagraphSummary = The following table summarises the configuration of the automation account(s) within the {0} subscription. + Heading = Automation Accounts + TableHeading = Automation Account + Name = Name + ResourceGroup = Resource Group + Location = Location + Subscription = Subscription + SubscriptionID = Subscription ID + State = State + RunbooksHeading = Runbooks + RunbookType = Type + LastModified = Last Modified + VariablesHeading = Variables + Encrypted = Encrypted + Description = Description + SchedulesHeading = Schedules + Enabled = Enabled + Frequency = Frequency + NextRun = Next Run + CredentialsHeading = Credentials + UserName = Username + Yes = Yes + No = No + Tags = Tags + None = None + ErrorMessage = Unable to collect Automation Account information: +'@ + +# Azure Diagnostic Settings (Get-AbrAzDiagnosticSetting) +GetAbrAzDiagnosticSetting = ConvertFrom-StringData @' + InfoLevel = DiagnosticSetting InfoLevel set at {0}. + Collecting = Collecting Azure Diagnostic Setting information. + SectionInfo = Azure Diagnostic Settings configure the export of platform logs and metrics from Azure resources to destinations such as Log Analytics workspaces, storage accounts, and Event Hubs for monitoring, auditing, and analysis. + ParagraphDetail = The following sections detail the configuration of the diagnostic setting(s) within the {0} subscription. + ParagraphSummary = The following table summarises the configuration of the diagnostic setting(s) within the {0} subscription. + Heading = Diagnostic Settings + TableHeading = Diagnostic Setting + ResourceName = Resource Name + ResourceType = Resource Type + ResourceGroup = Resource Group + Name = Name + Location = Location + Subscription = Subscription + SubscriptionID = Subscription ID + LogAnalyticsWorkspace = Log Analytics Workspace + StorageAccount = Storage Account + EventHub = Event Hub + LogCategoriesEnabled = Log Categories (Enabled) + MetricsEnabled = Metrics Enabled + Yes = Yes + No = No + None = None + ErrorMessage = Unable to collect Diagnostic Setting information: +'@ + +# Azure DNS Forwarding Rulesets (Get-AbrAzDnsForwardingRuleset) +GetAbrAzDnsForwardingRuleset = ConvertFrom-StringData @' + InfoLevel = DnsForwardingRuleset InfoLevel set at {0}. + Collecting = Collecting Azure DNS Forwarding Ruleset information. + SectionInfo = Azure DNS Forwarding Rulesets define sets of conditional forwarding rules that direct DNS queries to specific DNS servers. They are associated with DNS Private Resolver outbound endpoints and linked to virtual networks to control DNS resolution behaviour. + ParagraphDetail = The following sections detail the configuration of the DNS forwarding ruleset(s) within the {0} subscription. + ParagraphSummary = The following table summarises the configuration of the DNS forwarding ruleset(s) within the {0} subscription. + Heading = DNS Forwarding Rulesets + TableHeading = DNS Forwarding Ruleset + Name = Name + ResourceGroup = Resource Group + Location = Location + Subscription = Subscription + SubscriptionID = Subscription ID + ForwardingRules = Forwarding Rules + VirtualNetworkLinks = VNet Links + OutboundEndpoints = Outbound Endpoints + ProvisioningState = Provisioning State + ForwardingRulesHeading = Forwarding Rules + RuleName = Name + DomainName = Domain Name + TargetServers = Target DNS Servers + RuleState = State + VNetLinksHeading = Virtual Network Links + LinkName = Name + VirtualNetwork = Virtual Network + Tags = Tags + None = None + ErrorMessage = Unable to collect DNS Forwarding Ruleset information: +'@ + +# Azure Network Virtual Appliance (Get-AbrAzNetworkVirtualAppliance) +GetAbrAzNetworkVirtualAppliance = ConvertFrom-StringData @' + InfoLevel = NetworkVirtualAppliance InfoLevel set at {0}. + Collecting = Collecting Azure Network Virtual Appliance information. + Processing = Processing Azure Network Virtual Appliance '{0}'. + SectionInfo = Network Virtual Appliances (NVAs) are third-party network and security products deployed as virtual machines in Azure. Common NVA workloads include next-generation firewalls, SD-WAN gateways, WAN optimisers, and application delivery controllers. NVAs are identified by their Azure Marketplace image publisher and, optionally, by a resource tag. User-defined routes (UDRs) with a next-hop type of Virtual Appliance are cross-referenced to show which traffic flows are steered through each NVA. + ParagraphSummary = The following table summarises the Network Virtual Appliances identified within the {0} subscription. + ParagraphDetail = The following sections detail the configuration of the Network Virtual Appliances identified within the {0} subscription. + Heading = Network Virtual Appliances + TableHeading = Network Virtual Appliance + TableHeadings = Network Virtual Appliances + Name = Name + ResourceGroup = Resource Group + Location = Location + Subscription = Subscription + SubscriptionID = Subscription ID + Vendor = Vendor + Publisher = Publisher + Offer = Offer + Sku = SKU + ImageVersion = Image Version + Status = Status + Running = Running + Deallocated = Deallocated + Size = VM Size + PrivateIPAddress = Private IP Address + VirtualNetworkSubnet = Virtual Network / Subnet + NetworkInterfaces = Network Interfaces + DetectedBy = Detected By + DetectedByPublisher = Marketplace publisher + DetectedByTag = Resource tag + DetectedBoth = Marketplace publisher and resource tag + TagIdentified = Tag-identified NVA + AssociatedRoutes = Associated UDR Routes + NoAssociatedRoutes = No UDR routes with a Virtual Appliance next hop were found pointing to this NVA. + RouteTable = Route Table + RouteName = Route Name + AddressPrefix = Address Prefix + NextHopIpAddress = Next Hop IP Address + Tags = Tags + None = None +'@ + } \ No newline at end of file diff --git a/AsBuiltReport.Microsoft.Azure/Language/en-US/MicrosoftAzure.psd1 b/AsBuiltReport.Microsoft.Azure/Language/en-US/MicrosoftAzure.psd1 index 0b2cb28..3100d98 100644 --- a/AsBuiltReport.Microsoft.Azure/Language/en-US/MicrosoftAzure.psd1 +++ b/AsBuiltReport.Microsoft.Azure/Language/en-US/MicrosoftAzure.psd1 @@ -11,6 +11,7 @@ InvokeAsBuiltReportMicrosoftAzure = ConvertFrom-StringData @' InfoLevelNotFound = InfoLevel for '{0}' not found. FunctionNotFound = Function '{0}' for section '{1}' not found. SectionError = Error processing section '{0}': {1}" + AzureApiError = Azure API call failed: {0} TenantNotFound = Azure Tenant '{0}' not found. TokenAccountIdRequired = Azure token authentication requires AccountId parameter. Use {0} with {1} @{{AccountId="user@domain.com"}}. ConnectingWithToken = Connecting to Azure using token for account {0} in tenant {1}. @@ -288,7 +289,7 @@ GetAbrAsrProtectedItems = ConvertFrom-StringData @' InfoLevel = SiteRecovery InfoLevel set at {0}. Collecting = Collecting Azure Site Recovery information '{0}'. CollectingItems = Collecting Azure Site Recovery Protected Items information. - ParagraghSummary = The following tables provides information for the Azure Site Recovery protected items within the {0} subscription. + ParagraphSummary = The following table provides information for the Azure Site Recovery protected items within the {0} subscription. Heading = Protected Items TableHeading = Protected Items SubHeading = Site Recovery @@ -301,6 +302,69 @@ GetAbrAsrProtectedItems = ConvertFrom-StringData @' ActiveLocation = Active Location TargetLocation = Target Location FailoverHealth = Failover Health + NoTestFailover = No test failover has been performed + ParagraphDetail = The following sections detail the configuration of the Azure Site Recovery protected items within the {0} subscription. + ReplicationProvider = Replication Provider + Rpo = RPO (mins) + LastRpoCalculated = Last RPO Calculated + LastHeartbeat = Last Heartbeat + RecoveryVmSize = Recovery VM Size + RecoveryAvailabilityZone = Recovery Availability Zone + NotAvailable = N/A + None = None +'@ + +# Azure Site Recovery Replication Policies (Get-AbrAzAsrPolicy) +GetAbrAzAsrPolicy = ConvertFrom-StringData @' + InfoLevel = AsrPolicy InfoLevel set at {0}. + Collecting = Collecting Azure Site Recovery Policy information for '{0}'. + SectionInfo = Azure Site Recovery replication policies define recovery point objectives (RPO) and recovery point history for replicated virtual machines. + Heading = Replication Policies + TableHeadings = Replication Policies + ParagraphSummary = The following table summarises the Azure Site Recovery replication policies configured for the {0} recovery services vault. + ParagraphDetail = The following sections detail the Azure Site Recovery replication policies configured for the {0} recovery services vault. + Name = Name + Provider = Provider + RpoThreshold = RPO Threshold (mins) + RecoveryPointHistory = Recovery Point History (hrs) + AppConsistentFrequency = App-Consistent Snapshot (mins) + CrashConsistentFrequency = Crash-Consistent Snapshot (mins) + MultiVmSync = Multi-VM Sync + NotApplicable = N/A +'@ + +# Azure Site Recovery Recovery Plans (Get-AbrAzAsrRecoveryPlan) +GetAbrAzAsrRecoveryPlan = ConvertFrom-StringData @' + InfoLevel = AsrRecoveryPlan InfoLevel set at {0}. + Collecting = Collecting Azure Site Recovery Recovery Plan information for '{0}'. + SectionInfo = Azure Site Recovery recovery plans orchestrate the failover and recovery of groups of virtual machines, enabling coordinated DR operations. + Heading = Recovery Plans + TableHeadings = Recovery Plans + ParagraphSummary = The following table summarises the Azure Site Recovery recovery plans configured for the {0} recovery services vault. + ParagraphDetail = The following sections detail the Azure Site Recovery recovery plans configured for the {0} recovery services vault. + Name = Name + PrimaryFabric = Primary Location + RecoveryFabric = Recovery Location + GroupCount = Groups + ProtectedItemCount = Protected Items + FailoverDeploymentModel = Failover Deployment Model + None = None +'@ + +# Azure Site Recovery Network Mappings (Get-AbrAzAsrNetworkMapping) +GetAbrAzAsrNetworkMapping = ConvertFrom-StringData @' + InfoLevel = AsrNetworkMapping InfoLevel set at {0}. + Collecting = Collecting Azure Site Recovery Network Mapping information for '{0}'. + SectionInfo = Azure Site Recovery network mappings define the relationship between source and target virtual networks used during failover operations. + Heading = Network Mappings + TableHeadings = Network Mappings + ParagraphSummary = The following table summarises the Azure Site Recovery network mappings configured for the {0} recovery services vault. + ParagraphDetail = The following sections detail the Azure Site Recovery network mappings configured for the {0} recovery services vault. + Name = Name + PrimaryNetwork = Primary Network + RecoveryNetwork = Recovery Network + MappingState = Mapping State + None = None '@ # Azure Availability Sets (Get-AbrAzAvailabilitySet) @@ -422,6 +486,7 @@ GetAbrAzStorageAccount = ConvertFrom-StringData @' Disabled = Disabled Unknown = Unknown Created = Created + Locks = Locks Tags = Tags None = None '@ @@ -484,6 +549,7 @@ GetAbrAzFirewall = ConvertFrom-StringData @' NatRules = NAT Rules NetworkRules = Network Rules AppRules = Application Rules + Locks = Locks Tags = Tags None = None '@ @@ -592,6 +658,7 @@ GetAbrAzKeyVault = ConvertFrom-StringData @' Disabled = Disabled NoAccessEnabled = No access enabled EnabledDays = Enabled ({0} days) + Locks = Locks Tags = Tags None = None days = days @@ -665,7 +732,7 @@ GetAbrAzLoadBalancer = ConvertFrom-StringData @' Heading = Load Balancers TableHeading = Load Balancer TableHeadings = Load Balancers - LoadBalancerImage = Load Balancer Image + Image = Load Balancer Image ImageError = Unable to display Load Balancer image Name = Name ResourceGroup = Resource Group @@ -715,6 +782,7 @@ GetAbrAzLogAnalyticsWorkspace = ConvertFrom-StringData @' Disabled = Disabled Unknown = Unknown NoQuota = No Quota Set + Locks = Locks Tags = Tags None = None '@ @@ -859,6 +927,13 @@ GetAbrAzRecoveryServicesVault = ConvertFrom-StringData @' ProvisioningState = Provisioning State PrivateEndpointStateForBackup = Private Endpoint State for Backup PrivateEndpointStateForSiteRecovery = Private Endpoint State for Site Recovery + StorageRedundancy = Storage Redundancy + CrossRegionRestore = Cross Region Restore + SoftDeleteState = Soft Delete State + SoftDeleteRetentionDays = Soft Delete Retention (Days) + ImmutabilityState = Immutability State + PublicNetworkAccess = Public Network Access + Locks = Locks Tags = Tags None = None '@ @@ -883,6 +958,7 @@ GetAbrAzRouteTable = ConvertFrom-StringData @' AddressPrefix = Address Prefix NextHopType = Next Hop Type NextHopIpAddress = Next Hop IP Address + Locks = Locks Tags = Tags None = None '@ @@ -1063,6 +1139,7 @@ GetAbrAzVirtualNetwork = ConvertFrom-StringData @' Subnets = Subnets DnsServers = DNS Servers Default = Default (Azure-provided) + Locks = Locks Tags = Tags None = None '@ @@ -1254,4 +1331,588 @@ GetAbrAzDesktopVirtualization = ConvertFrom-StringData @' Allowed = Allowed '@ + +# Azure NetApp Files (Get-AbrAzNetAppFiles) +GetAbrAzNetAppFiles = ConvertFrom-StringData @' + InfoLevel = NetAppFiles InfoLevel set at {0}. + Collecting = Collecting Azure NetApp Files information. + SectionInfo = Azure NetApp Files is an enterprise-class, high-performance, metered file storage service running on Azure. It supports SMB, NFSv3, NFSv4.1, and dual-protocol volumes with integrated snapshots, cross-region replication, and backup. + AccountsSummary = The following table summarizes the NetApp Files accounts within the {0} subscription. + PoolsSummary = The following table summarizes the capacity pools within the {0} subscription. + VolumesSummary = The following table summarizes the volumes within the {0} subscription. + SnapshotPoliciesSummary = The following table summarizes the snapshot policies within the {0} subscription. + BackupPoliciesSummary = The following table summarizes the backup policies within the {0} subscription. + AdConfigIntro = Active Directory configuration for NetApp account '{0}'. + MountTargetsIntro = Mount targets for volume '{0}'. + WarningPoolAllocation = WARNING: Capacity pool '{0}' is {1}% allocated ({2} GiB of {3} GiB). + WarningAdStatus = WARNING: Active Directory configuration for account '{0}' has status '{1}'. + Heading = Azure NetApp Files + AccountsHeading = NetApp Accounts + PoolsHeading = Capacity Pools + VolumesHeading = Volumes + SnapshotPoliciesHeading = Snapshot Policies + BackupPoliciesHeading = Backup Policies + ActiveDirectoryHeading = Active Directory Configuration + EncryptionHeading = Encryption Configuration + ExportPolicyHeading = Export Policy Rules + MountTargetsHeading = Mount Targets + DataProtectionHeading = Data Protection + SnapshotsHeading = Snapshots + QuotaRulesHeading = Volume Quota Rules + Name = Name + ResourceGroup = Resource Group + Location = Location + Tags = Tags + Status = Status + Type = Type + Account = Account + Pool = Pool + Volume = Volume + ServiceLevel = Service Level + QosType = QoS Type + SizeTiB = Size (TiB) + SizeGiB = Size (GiB) + QuotaGiB = Quota (GiB) + AllocatedGiB = Allocated (GiB) + PercentAllocated = % Allocated + VolumeCount = Volumes + TotalThroughput = Total Throughput (MiB/s) + UtilizedThroughput = Utilized Throughput (MiB/s) + CoolAccess = Cool Access + EncryptionType = Encryption Type + EncryptionKeySource = Encryption Key Source + EncryptionKeyVault = Key Vault URI + EncryptionKeyName = Key Name + Protocol = Protocol + Subnet = Delegated Subnet + Zone = Availability Zone + Throughput = Throughput (MiB/s) + ActualThroughput = Actual Throughput (MiB/s) + SecurityStyle = Security Style + UnixPermission = Unix Permissions + SnapshotPolicy = Snapshot Policy + BackupPolicy = Backup Policy + SnapshotDirVisible = Snapshot Dir Visible + NetworkFeatures = Network Features + CoolnessPeriod = Coolness Period (days) + TieringPolicy = Tiering Policy + RetrievalPolicy = Retrieval Policy + VolumeType = Volume Type + ProvisioningState = Provisioning State + KerberosEnabled = Kerberos + LdapEnabled = LDAP + SmbEncryption = SMB Encryption + SmbContinuouslyAvailable = SMB Continuously Available + SmbAccessBasedEnumeration = SMB ABE + FileSystemId = File System ID + Domain = Domain + Username = Username + Site = AD Site + OrganizationalUnit = Organizational Unit + SmbServerName = SMB Server Name + AesEncryption = AES Encryption + LdapSigning = LDAP Signing + EncryptDCConnection = Encrypt DC Connection + AllowLocalNfsUsersWithLdap = Allow Local NFS Users with LDAP + DnsServers = DNS Servers + Enabled = Enabled + HourlySchedule = Hourly Schedule + DailySchedule = Daily Schedule + WeeklySchedule = Weekly Schedule + MonthlySchedule = Monthly Schedule + SnapshotsToKeep = Snapshots to Keep + Minute = Minute + Hour = Hour + Day = Day of Week + DaysOfMonth = Days of Month + DailyBackups = Daily Backups to Keep + WeeklyBackups = Weekly Backups to Keep + MonthlyBackups = Monthly Backups to Keep + RuleIndex = Rule + AllowedClients = Allowed Clients + UnixReadWrite = NFS Read/Write + UnixReadOnly = NFS Read-Only + Nfsv3 = NFSv3 + Nfsv41 = NFSv4.1 + HasRootAccess = Root Access + Kerberos5ReadWrite = Kerberos 5 R/W + Kerberos5iReadWrite = Kerberos 5i R/W + Kerberos5pReadWrite = Kerberos 5p R/W + ChownMode = Chown Mode + IpAddress = IP Address + SmbServerFqdn = SMB Server FQDN + Created = Created + None = None + NoPolicy = No Policy Attached + NotConfigured = Not Configured + InUse = InUse + PlatformManaged = Platform-Managed + CustomerManaged = Customer-Managed + Yes = Yes + No = No +'@ + +# Azure Management Groups (Get-AbrAzManagementGroup) +GetAbrAzManagementGroup = ConvertFrom-StringData @' + InfoLevel = ManagementGroup InfoLevel set at {0}. + Collecting = Collecting Azure Management Group information. + SectionInfo = Azure Management Groups provide a governance scope above subscriptions. All subscriptions within a management group automatically inherit the conditions applied to the management group, enabling consistent policy and access control across your entire Azure estate. + Heading = Management Groups + TableHeading = Management Groups + DiagramHeading = Management Group Hierarchy + DiagramAltText = Azure management group hierarchy diagram + DiagramError = Unable to generate Management Group hierarchy diagram: {0}. + Name = Name + Id = Management Group ID + ParentName = Parent Group + ChildGroupCount = Child Groups + SubscriptionCount = Subscriptions + ResourceGroup = Resource Group + Location = Location + NotFound = No Management Groups found. + None = None + ErrorMessage = Unable to collect Management Group information: +'@ + +# Azure Private DNS Zones (Get-AbrAzPrivateDnsZone) +GetAbrAzPrivateDnsZone = ConvertFrom-StringData @' + InfoLevel = PrivateDnsZone InfoLevel set at {0}. + Collecting = Collecting Azure Private DNS Zone information. + SectionInfo = Azure Private DNS Zones provide a reliable, secure DNS service to manage and resolve domain names in a virtual network without the need to add a custom DNS solution. Private DNS zones are not visible on the public internet and allow you to use your own custom domain names rather than the Azure-provided names. + ParagraphDetail = The following sections detail the configuration of the private DNS zone(s) within the {0} subscription. + ParagraphSummary = The following table summarizes the configuration of the private DNS zone(s) within the {0} subscription. + Heading = Private DNS Zones + TableHeading = Private DNS Zone + Name = Name + ResourceGroup = Resource Group + Location = Location + Subscription = Subscription + SubscriptionID = Subscription ID + RecordSets = Record Sets + MaxRecordSets = Max Record Sets + VirtualNetworkLinks = Virtual Network Links + VNetLinksWithRegistration = VNet Links with Auto Registration + ProvisioningState = Provisioning State + LinkName = Link Name + VirtualNetwork = Virtual Network + AutoRegistration = Auto Registration + VirtualNetworkLinkState = Link State + Locks = Locks + Tags = Tags + None = None + ErrorMessage = Unable to collect Private DNS Zone information: +'@ + +# Azure Virtual Network Gateway (Get-AbrAzVirtualNetworkGateway) +GetAbrAzVirtualNetworkGateway = ConvertFrom-StringData @' + InfoLevel = VirtualNetworkGateway InfoLevel set at {0}. + Collecting = Collecting Azure Virtual Network Gateway information. + SectionInfo = Azure Virtual Network Gateways connect your on-premises networks to Azure through Site-to-Site VPNs, and connect Azure virtual networks to each other through VNet-to-VNet VPNs. ExpressRoute gateways enable private, dedicated connections to Azure without traversing the public internet. + ParagraphDetail = The following sections detail the configuration of the virtual network gateway(s) within the {0} subscription. + ParagraphSummary = The following table summarizes the configuration of the virtual network gateway(s) within the {0} subscription. + Heading = Virtual Network Gateways + TableHeading = Virtual Network Gateway + Name = Name + ResourceGroup = Resource Group + Location = Location + Subscription = Subscription + SubscriptionID = Subscription ID + VirtualNetwork = Virtual Network + GatewayType = Gateway Type + VpnType = VPN Type + SKU = SKU + Generation = Generation + ActiveActive = Active-Active + EnableBgp = BGP Enabled + BgpAsn = BGP ASN + BgpPeeringAddress = BGP Peering Address + ProvisioningState = Provisioning State + Connections = Connections + ConnectionName = Name + ConnectionType = Connection Type + ConnectionStatus = Connection Status + ConnectionProtocol = Protocol + RoutingWeight = Routing Weight + NotApplicable = N/A + Locks = Locks + Tags = Tags + None = None + ErrorMessage = Unable to collect Virtual Network Gateway information: +'@ + +# Azure DDoS Protection Plan (Get-AbrAzDdosProtectionPlan) +GetAbrAzDdosProtectionPlan = ConvertFrom-StringData @' + InfoLevel = DDoSProtectionPlan InfoLevel set at {0}. + Collecting = Collecting Azure DDoS Protection Plan information. + SectionInfo = Azure DDoS Protection Plans provide enhanced DDoS mitigation capabilities for all resources in a virtual network. They offer telemetry, alerting, and detailed analytics to help protect your Azure resources against DDoS attacks. + ParagraphDetail = The following sections detail the configuration of the DDoS Protection Plan(s) within the {0} subscription. + ParagraphSummary = The following table summarizes the configuration of the DDoS Protection Plan(s) within the {0} subscription. + Heading = DDoS Protection Plans + TableHeading = DDoS Protection Plan + Name = Name + ResourceGroup = Resource Group + Location = Location + Subscription = Subscription + SubscriptionID = Subscription ID + ProtectedVirtualNetworks = Protected Virtual Networks + VirtualNetworkName = Virtual Network + ProvisioningState = Provisioning State + Locks = Locks + Tags = Tags + None = None + ErrorMessage = Unable to collect DDoS Protection Plan information: +'@ + +# Azure Application Gateway (Get-AbrAzApplicationGateway) +GetAbrAzApplicationGateway = ConvertFrom-StringData @' + InfoLevel = ApplicationGateway InfoLevel set at {0}. + Collecting = Collecting Azure Application Gateway information. + SectionInfo = Azure Application Gateways are web traffic load balancers that operate at Layer 7. They support features such as SSL/TLS termination, URL-based routing, multi-site hosting, session affinity, and Web Application Firewall integration. + ParagraphDetail = The following sections detail the configuration of the application gateway(s) within the {0} subscription. + ParagraphSummary = The following table summarizes the configuration of the application gateway(s) within the {0} subscription. + Heading = Application Gateways + TableHeading = Application Gateway + Name = Name + ResourceGroup = Resource Group + Location = Location + Subscription = Subscription + SubscriptionID = Subscription ID + VirtualNetwork = Virtual Network + Subnet = Subnet + SKU = SKU + Tier = Tier + Capacity = Capacity + WafEnabled = WAF Enabled + WafMode = WAF Mode + Http2Enabled = HTTP/2 Enabled + FrontendIPs = Frontend IPs + OperationalState = Operational State + ProvisioningState = Provisioning State + Listeners = HTTP Listeners + ListenerName = Listener + Protocol = Protocol + Port = Port + HostName = Host Name + BackendPools = Backend Address Pools + PoolName = Pool Name + BackendTargets = Backend Targets + RoutingRules = Request Routing Rules + RuleName = Rule Name + RuleType = Rule Type + BackendPool = Backend Pool + BackendHttpSettings = HTTP Settings + Unlimited = Unlimited + NotApplicable = N/A + Tags = Tags + None = None + ErrorMessage = Unable to collect Application Gateway information: +'@ + +# Azure Data Collection Rules (Get-AbrAzDataCollectionRule) +GetAbrAzDataCollectionRule = ConvertFrom-StringData @' + InfoLevel = DataCollectionRule InfoLevel set at {0}. + Collecting = Collecting Azure Data Collection Rule information. + SectionInfo = Azure Data Collection Rules define what monitoring data to collect, from where, and where to send it. They specify data sources such as performance counters, Windows event logs, and Syslog, and route that data to Log Analytics workspaces or other destinations. + ParagraphDetail = The following sections detail the configuration of the data collection rule(s) within the {0} subscription. + ParagraphSummary = The following table summarizes the configuration of the data collection rule(s) within the {0} subscription. + Heading = Data Collection Rules + TableHeading = Data Collection Rule + Name = Name + ResourceGroup = Resource Group + Location = Location + Subscription = Subscription + SubscriptionID = Subscription ID + Description = Description + DataSources = Data Sources + LogAnalyticsDestinations = Log Analytics Destinations + ProvisioningState = Provisioning State + PerformanceCounters = Performance Counters + WindowsEventLogs = Windows Event Logs + Syslog = Syslog + Extensions = Extensions + LogFiles = Log Files + Destinations = Log Analytics Destinations + DestinationName = Name + WorkspaceId = Workspace Resource ID + DataFlows = Data Flows + Streams = Streams + Tags = Tags + None = None + ErrorMessage = Unable to collect Data Collection Rule information: +'@ + +# Azure Public IP Addresses (Get-AbrAzPublicIpAddress) +GetAbrAzPublicIpAddress = ConvertFrom-StringData @' + InfoLevel = PublicIpAddress InfoLevel set at {0}. + Collecting = Collecting Azure Public IP Address information. + SectionInfo = Azure Public IP Addresses provide internet-facing IP addresses for resources such as virtual machines, load balancers, VPN gateways, and application gateways. They support both dynamic and static allocation and are available in Basic and Standard SKUs. + ParagraphDetail = The following sections detail the configuration of the public IP address(es) within the {0} subscription. + ParagraphSummary = The following table summarizes the configuration of the public IP address(es) within the {0} subscription. + Heading = Public IP Addresses + TableHeading = Public IP Address + Name = Name + ResourceGroup = Resource Group + Location = Location + Subscription = Subscription + SubscriptionID = Subscription ID + SKU = SKU + Tier = Tier + IpVersion = IP Version + AllocationMethod = Allocation Method + IpAddress = IP Address + DnsLabel = DNS Label + Fqdn = FQDN + Zones = Availability Zones + AssociatedResource = Associated Resource + ProvisioningState = Provisioning State + NotAssigned = Not Assigned + Tags = Tags + None = None + ErrorMessage = Unable to collect Public IP Address information: +'@ + +# Azure Network Watchers (Get-AbrAzNetworkWatcher) +GetAbrAzNetworkWatcher = ConvertFrom-StringData @' + InfoLevel = NetworkWatcher InfoLevel set at {0}. + Collecting = Collecting Azure Network Watcher information. + SectionInfo = Azure Network Watcher provides network monitoring and diagnostic capabilities per region. NSG Flow Logs capture information about IP traffic flowing through Network Security Groups and can optionally route data to a Log Analytics workspace via Traffic Analytics. + ParagraphDetail = The following sections detail the configuration of the network watcher(s) within the {0} subscription. + ParagraphSummary = The following table summarizes the configuration of the network watcher(s) within the {0} subscription. + Heading = Network Watchers + TableHeading = Network Watcher + Name = Name + ResourceGroup = Resource Group + Location = Location + Subscription = Subscription + SubscriptionID = Subscription ID + FlowLogs = Flow Logs + ProvisioningState = Provisioning State + FlowLogsHeading = NSG Flow Logs + FlowLogName = Name + TargetResource = Target Resource + FlowLogEnabled = Enabled + RetentionDays = Retention (Days) + TrafficAnalytics = Traffic Analytics + StorageAccount = Storage Account + Enabled = Enabled + Disabled = Disabled + Unlimited = Unlimited + Tags = Tags + None = None + ErrorMessage = Unable to collect Network Watcher information: +'@ + +# Azure VM Scale Sets (Get-AbrAzVmScaleSet) +GetAbrAzVmScaleSet = ConvertFrom-StringData @' + InfoLevel = VmScaleSet InfoLevel set at {0}. + Collecting = Collecting Azure Virtual Machine Scale Set information. + SectionInfo = Azure Virtual Machine Scale Sets (VMSS) enable deployment and management of a group of identical, load-balanced virtual machines. They support autoscaling, multiple availability zones, and flexible or uniform orchestration modes. + ParagraphDetail = The following sections detail the configuration of the virtual machine scale set(s) within the {0} subscription. + ParagraphSummary = The following table summarizes the configuration of the virtual machine scale set(s) within the {0} subscription. + Heading = VM Scale Sets + TableHeading = VM Scale Set + Name = Name + ResourceGroup = Resource Group + Location = Location + Subscription = Subscription + SubscriptionID = Subscription ID + VmSize = VM Size + Instances = Instances + OrchestrationMode = Orchestration Mode + UpgradePolicy = Upgrade Policy + Overprovision = Overprovision + SinglePlacementGroup = Single Placement Group + Zones = Availability Zones + Identity = Identity + ProvisioningState = Provisioning State + Tags = Tags + None = None + ErrorMessage = Unable to collect Virtual Machine Scale Set information: +'@ + +# Azure Maintenance Configurations (Get-AbrAzMaintenanceConfiguration) +GetAbrAzMaintenanceConfiguration = ConvertFrom-StringData @' + InfoLevel = MaintenanceConfiguration InfoLevel set at {0}. + Collecting = Collecting Azure Maintenance Configuration information. + SectionInfo = Azure Maintenance Configurations define scheduled maintenance windows for Azure resources. They control when platform updates, OS patching, and other maintenance activities are applied, reducing unplanned downtime. + ParagraphDetail = The following sections detail the configuration of the maintenance configuration(s) within the {0} subscription. + ParagraphSummary = The following table summarizes the configuration of the maintenance configuration(s) within the {0} subscription. + Heading = Maintenance Configurations + TableHeading = Maintenance Configuration + Name = Name + ResourceGroup = Resource Group + Location = Location + Subscription = Subscription + SubscriptionID = Subscription ID + Scope = Scope + Visibility = Visibility + StartDateTime = Start Date/Time + ExpirationDateTime = Expiration Date/Time + Duration = Duration + RecurEvery = Recurrence + TimeZone = Time Zone + NotConfigured = Not Configured + NoExpiry = No Expiry + Tags = Tags + None = None + ErrorMessage = Unable to collect Maintenance Configuration information: +'@ + +# Azure User Assigned Managed Identities (Get-AbrAzUserAssignedManagedIdentity) +GetAbrAzUserAssignedManagedIdentity = ConvertFrom-StringData @' + InfoLevel = UserAssignedManagedIdentity InfoLevel set at {0}. + Collecting = Collecting Azure User Assigned Managed Identity information. + SectionInfo = Azure User Assigned Managed Identities are standalone Azure resources that provide an Azure AD identity for services to use when authenticating to resources that support Azure Active Directory authentication. They exist independently of any Azure service or resource and can be assigned to multiple resources. + ParagraphDetail = The following sections detail the configuration of the user assigned managed identity/identities within the {0} subscription. + ParagraphSummary = The following table summarizes the configuration of the user assigned managed identity/identities within the {0} subscription. + Heading = User Assigned Managed Identities + TableHeading = User Assigned Managed Identity + Name = Name + ResourceGroup = Resource Group + Location = Location + Subscription = Subscription + SubscriptionID = Subscription ID + ClientID = Client ID + PrincipalID = Principal ID + TenantID = Tenant ID + Tags = Tags + None = None + ErrorMessage = Unable to collect User Assigned Managed Identity information: +'@ + +# Azure Automation Accounts (Get-AbrAzAutomationAccount) +GetAbrAzAutomationAccount = ConvertFrom-StringData @' + InfoLevel = AutomationAccount InfoLevel set at {0}. + Collecting = Collecting Azure Automation Account information. + SectionInfo = Azure Automation Accounts provide cloud-based automation and configuration management, supporting process automation via runbooks, configuration management, and update management across Azure and on-premises environments. + ParagraphDetail = The following sections detail the configuration of the automation account(s) within the {0} subscription. + ParagraphSummary = The following table summarizes the configuration of the automation account(s) within the {0} subscription. + Heading = Automation Accounts + TableHeading = Automation Account + Name = Name + ResourceGroup = Resource Group + Location = Location + Subscription = Subscription + SubscriptionID = Subscription ID + State = State + RunbooksHeading = Runbooks + RunbookType = Type + LastModified = Last Modified + VariablesHeading = Variables + Encrypted = Encrypted + Description = Description + SchedulesHeading = Schedules + Enabled = Enabled + Frequency = Frequency + NextRun = Next Run + CredentialsHeading = Credentials + UserName = Username + Yes = Yes + No = No + Tags = Tags + None = None + ErrorMessage = Unable to collect Automation Account information: +'@ + +# Azure Diagnostic Settings (Get-AbrAzDiagnosticSetting) +GetAbrAzDiagnosticSetting = ConvertFrom-StringData @' + InfoLevel = DiagnosticSetting InfoLevel set at {0}. + Collecting = Collecting Azure Diagnostic Setting information. + SectionInfo = Azure Diagnostic Settings configure the export of platform logs and metrics from Azure resources to destinations such as Log Analytics workspaces, storage accounts, and Event Hubs for monitoring, auditing, and analysis. + ParagraphDetail = The following sections detail the configuration of the diagnostic setting(s) within the {0} subscription. + ParagraphSummary = The following table summarizes the configuration of the diagnostic setting(s) within the {0} subscription. + Heading = Diagnostic Settings + TableHeading = Diagnostic Setting + ResourceName = Resource Name + ResourceType = Resource Type + ResourceGroup = Resource Group + Name = Name + Location = Location + Subscription = Subscription + SubscriptionID = Subscription ID + LogAnalyticsWorkspace = Log Analytics Workspace + StorageAccount = Storage Account + EventHub = Event Hub + LogCategoriesEnabled = Log Categories (Enabled) + MetricsEnabled = Metrics Enabled + Yes = Yes + No = No + None = None + ErrorMessage = Unable to collect Diagnostic Setting information: +'@ + +# Azure DNS Forwarding Rulesets (Get-AbrAzDnsForwardingRuleset) +GetAbrAzDnsForwardingRuleset = ConvertFrom-StringData @' + InfoLevel = DnsForwardingRuleset InfoLevel set at {0}. + Collecting = Collecting Azure DNS Forwarding Ruleset information. + SectionInfo = Azure DNS Forwarding Rulesets define sets of conditional forwarding rules that direct DNS queries to specific DNS servers. They are associated with DNS Private Resolver outbound endpoints and linked to virtual networks to control DNS resolution behaviour. + ParagraphDetail = The following sections detail the configuration of the DNS forwarding ruleset(s) within the {0} subscription. + ParagraphSummary = The following table summarizes the configuration of the DNS forwarding ruleset(s) within the {0} subscription. + Heading = DNS Forwarding Rulesets + TableHeading = DNS Forwarding Ruleset + Name = Name + ResourceGroup = Resource Group + Location = Location + Subscription = Subscription + SubscriptionID = Subscription ID + ForwardingRules = Forwarding Rules + VirtualNetworkLinks = VNet Links + OutboundEndpoints = Outbound Endpoints + ProvisioningState = Provisioning State + ForwardingRulesHeading = Forwarding Rules + RuleName = Name + DomainName = Domain Name + TargetServers = Target DNS Servers + RuleState = State + VNetLinksHeading = Virtual Network Links + LinkName = Name + VirtualNetwork = Virtual Network + Tags = Tags + None = None + ErrorMessage = Unable to collect DNS Forwarding Ruleset information: +'@ + +# Azure Network Virtual Appliance (Get-AbrAzNetworkVirtualAppliance) +GetAbrAzNetworkVirtualAppliance = ConvertFrom-StringData @' + InfoLevel = NetworkVirtualAppliance InfoLevel set at {0}. + Collecting = Collecting Azure Network Virtual Appliance information. + Processing = Processing Azure Network Virtual Appliance '{0}'. + SectionInfo = Network Virtual Appliances (NVAs) are third-party network and security products deployed as virtual machines in Azure. Common NVA workloads include next-generation firewalls, SD-WAN gateways, WAN optimisers, and application delivery controllers. NVAs are identified by their Azure Marketplace image publisher and, optionally, by a resource tag. User-defined routes (UDRs) with a next-hop type of Virtual Appliance are cross-referenced to show which traffic flows are steered through each NVA. + ParagraphSummary = The following table summarizes the Network Virtual Appliances identified within the {0} subscription. + ParagraphDetail = The following sections detail the configuration of the Network Virtual Appliances identified within the {0} subscription. + Heading = Network Virtual Appliances + TableHeading = Network Virtual Appliance + TableHeadings = Network Virtual Appliances + Name = Name + ResourceGroup = Resource Group + Location = Location + Subscription = Subscription + SubscriptionID = Subscription ID + Vendor = Vendor + Publisher = Publisher + Offer = Offer + Sku = SKU + ImageVersion = Image Version + Status = Status + Running = Running + Deallocated = Deallocated + Size = VM Size + PrivateIPAddress = Private IP Address + VirtualNetworkSubnet = Virtual Network / Subnet + NetworkInterfaces = Network Interfaces + DetectedBy = Detected By + DetectedByPublisher = Marketplace publisher + DetectedByTag = Resource tag + DetectedBoth = Marketplace publisher and resource tag + TagIdentified = Tag-identified NVA + AssociatedRoutes = Associated UDR Routes + NoAssociatedRoutes = No UDR routes with a Virtual Appliance next hop were found pointing to this NVA. + RouteTable = Route Table + RouteName = Route Name + AddressPrefix = Address Prefix + NextHopIpAddress = Next Hop IP Address + Tags = Tags + None = None +'@ + } \ No newline at end of file diff --git a/AsBuiltReport.Microsoft.Azure/Language/es-ES/MicrosoftAzure.psd1 b/AsBuiltReport.Microsoft.Azure/Language/es-ES/MicrosoftAzure.psd1 index b9ab285..31eb76d 100644 --- a/AsBuiltReport.Microsoft.Azure/Language/es-ES/MicrosoftAzure.psd1 +++ b/AsBuiltReport.Microsoft.Azure/Language/es-ES/MicrosoftAzure.psd1 @@ -11,6 +11,7 @@ InvokeAsBuiltReportMicrosoftAzure = ConvertFrom-StringData @' InfoLevelNotFound = InfoLevel para '{0}' no encontrado. FunctionNotFound = Función '{0}' para la sección '{1}' no encontrada. SectionError = Error al procesar la sección '{0}': {1}" + AzureApiError = Error en la llamada a la API de Azure: {0} TenantNotFound = Inquilino de Azure '{0}' no encontrado. TokenAccountIdRequired = La autenticación con token de Azure requiere el parámetro AccountId. Use {0} con {1} @{{AccountId="usuario@dominio.com"}}. ConnectingWithToken = Conectando a Azure usando token para la cuenta {0} en el inquilino {1}. @@ -288,7 +289,7 @@ GetAbrAsrProtectedItems = ConvertFrom-StringData @' InfoLevel = InfoLevel de SiteRecovery establecido en {0}. Collecting = Recopilando información de Azure Site Recovery '{0}'. CollectingItems = Recopilando información de elementos protegidos de Azure Site Recovery. - ParagraghSummary = Las siguientes tablas proporcionan información sobre los elementos protegidos de Azure Site Recovery en la suscripción {0}. + ParagraphSummary = La siguiente tabla proporciona información sobre los elementos protegidos de Azure Site Recovery en la suscripción {0}. Heading = Elementos protegidos TableHeading = Elementos protegidos SubHeading = Site Recovery @@ -301,6 +302,69 @@ GetAbrAsrProtectedItems = ConvertFrom-StringData @' ActiveLocation = Ubicación activa TargetLocation = Ubicación de destino FailoverHealth = Estado de conmutación por error + NoTestFailover = No se ha realizado ninguna conmutación por error de prueba + ParagraphDetail = Las siguientes secciones detallan la configuración de los elementos protegidos de Azure Site Recovery en la suscripción {0}. + ReplicationProvider = Proveedor de replicación + Rpo = RPO (mins) + LastRpoCalculated = Último cálculo de RPO + LastHeartbeat = Último latido + RecoveryVmSize = Tamaño de VM de recuperación + RecoveryAvailabilityZone = Zona de disponibilidad de recuperación + NotAvailable = N/D + None = Ninguna +'@ + +# Directivas de replicación de Azure Site Recovery (Get-AbrAzAsrPolicy) +GetAbrAzAsrPolicy = ConvertFrom-StringData @' + InfoLevel = Nivel de información de AsrPolicy establecido en {0}. + Collecting = Recopilando información de directivas de Azure Site Recovery para '{0}'. + SectionInfo = Las directivas de replicación de Azure Site Recovery definen los objetivos de punto de recuperación (RPO) y el historial de puntos de recuperación para las máquinas virtuales replicadas. + Heading = Directivas de replicación + TableHeadings = Directivas de replicación + ParagraphSummary = La siguiente tabla resume las directivas de replicación de Azure Site Recovery configuradas para el almacén de Recovery Services {0}. + ParagraphDetail = Las siguientes secciones detallan las directivas de replicación de Azure Site Recovery configuradas para el almacén de Recovery Services {0}. + Name = Nombre + Provider = Proveedor + RpoThreshold = Umbral de RPO (mins) + RecoveryPointHistory = Historial de puntos de recuperación (hrs) + AppConsistentFrequency = Instantánea coherente con la aplicación (mins) + CrashConsistentFrequency = Instantánea coherente con el bloqueo (mins) + MultiVmSync = Sincronización de varias VM + NotApplicable = N/D +'@ + +# Planes de recuperación de Azure Site Recovery (Get-AbrAzAsrRecoveryPlan) +GetAbrAzAsrRecoveryPlan = ConvertFrom-StringData @' + InfoLevel = Nivel de información de AsrRecoveryPlan establecido en {0}. + Collecting = Recopilando información del plan de recuperación de Azure Site Recovery para '{0}'. + SectionInfo = Los planes de recuperación de Azure Site Recovery coordinan la conmutación por error y la recuperación de grupos de máquinas virtuales, permitiendo operaciones de DR coordinadas. + Heading = Planes de recuperación + TableHeadings = Planes de recuperación + ParagraphSummary = La siguiente tabla resume los planes de recuperación de Azure Site Recovery configurados para el almacén de Recovery Services {0}. + ParagraphDetail = Las siguientes secciones detallan los planes de recuperación de Azure Site Recovery configurados para el almacén de Recovery Services {0}. + Name = Nombre + PrimaryFabric = Ubicación principal + RecoveryFabric = Ubicación de recuperación + GroupCount = Grupos + ProtectedItemCount = Elementos protegidos + FailoverDeploymentModel = Modelo de implementación de conmutación por error + None = Ninguno +'@ + +# Asignaciones de red de Azure Site Recovery (Get-AbrAzAsrNetworkMapping) +GetAbrAzAsrNetworkMapping = ConvertFrom-StringData @' + InfoLevel = Nivel de información de AsrNetworkMapping establecido en {0}. + Collecting = Recopilando información de asignación de red de Azure Site Recovery para '{0}'. + SectionInfo = Las asignaciones de red de Azure Site Recovery definen la relación entre las redes virtuales de origen y destino utilizadas durante las operaciones de conmutación por error. + Heading = Asignaciones de red + TableHeadings = Asignaciones de red + ParagraphSummary = La siguiente tabla resume las asignaciones de red de Azure Site Recovery configuradas para el almacén de Recovery Services {0}. + ParagraphDetail = Las siguientes secciones detallan las asignaciones de red de Azure Site Recovery configuradas para el almacén de Recovery Services {0}. + Name = Nombre + PrimaryNetwork = Red principal + RecoveryNetwork = Red de recuperación + MappingState = Estado de asignación + None = Ninguno '@ # Azure Availability Sets (Get-AbrAzAvailabilitySet) @@ -422,6 +486,7 @@ GetAbrAzStorageAccount = ConvertFrom-StringData @' Disabled = Deshabilitado Unknown = Desconocido Created = Creado + Locks = Bloqueos Tags = Etiquetas None = Ninguno '@ @@ -484,6 +549,7 @@ GetAbrAzFirewall = ConvertFrom-StringData @' NatRules = Reglas NAT NetworkRules = Reglas de red AppRules = Reglas de aplicación + Locks = Bloqueos Tags = Etiquetas None = Ninguno '@ @@ -592,6 +658,7 @@ GetAbrAzKeyVault = ConvertFrom-StringData @' Disabled = Deshabilitado NoAccessEnabled = Sin acceso habilitado EnabledDays = Habilitado ({0} días) + Locks = Bloqueos Tags = Etiquetas None = Ninguno days = días @@ -665,7 +732,7 @@ GetAbrAzLoadBalancer = ConvertFrom-StringData @' Heading = Equilibradores de carga TableHeading = Equilibrador de carga TableHeadings = Equilibradores de carga - LoadBalancerImage = Imagen de Load Balancer + Image = Imagen de Load Balancer ImageError = No se puede mostrar la imagen de Load Balancer Name = Nombre ResourceGroup = Grupo de recursos @@ -715,6 +782,7 @@ GetAbrAzLogAnalyticsWorkspace = ConvertFrom-StringData @' Disabled = Deshabilitado Unknown = Desconocido NoQuota = Sin cuota establecida + Locks = Bloqueos Tags = Etiquetas None = Ninguno '@ @@ -859,6 +927,13 @@ GetAbrAzRecoveryServicesVault = ConvertFrom-StringData @' ProvisioningState = Estado de aprovisionamiento PrivateEndpointStateForBackup = Estado de punto de conexión privado para copia de seguridad PrivateEndpointStateForSiteRecovery = Estado de punto de conexión privado para Site Recovery + StorageRedundancy = Redundancia de almacenamiento + CrossRegionRestore = Restauración entre regiones + SoftDeleteState = Estado de eliminación temporal + SoftDeleteRetentionDays = Retención de eliminación temporal (días) + ImmutabilityState = Estado de inmutabilidad + PublicNetworkAccess = Acceso a la red pública + Locks = Bloqueos Tags = Etiquetas None = Ninguno '@ @@ -883,6 +958,7 @@ GetAbrAzRouteTable = ConvertFrom-StringData @' AddressPrefix = Prefijo de dirección NextHopType = Tipo de próximo salto NextHopIpAddress = Dirección IP del próximo salto + Locks = Bloqueos Tags = Etiquetas None = Ninguno '@ @@ -1063,6 +1139,7 @@ GetAbrAzVirtualNetwork = ConvertFrom-StringData @' Subnets = Subredes DnsServers = Servidores DNS Default = Predeterminado (proporcionado por Azure) + Locks = Bloqueos Tags = Etiquetas None = Ninguno '@ @@ -1254,4 +1331,588 @@ GetAbrAzDesktopVirtualization = ConvertFrom-StringData @' Allowed = Permitido '@ + +# Azure NetApp Files (Get-AbrAzNetAppFiles) +GetAbrAzNetAppFiles = ConvertFrom-StringData @' + InfoLevel = InfoLevel de NetAppFiles establecido en {0}. + Collecting = Recopilando información de Azure NetApp Files. + SectionInfo = Azure NetApp Files es un servicio de almacenamiento de archivos medido, de alto rendimiento y de clase empresarial que se ejecuta en Azure. Admite volúmenes SMB, NFSv3, NFSv4.1 y de protocolo dual con instantáneas integradas, replicación entre regiones y copia de seguridad. + AccountsSummary = La siguiente tabla resume las cuentas de NetApp Files en la suscripción {0}. + PoolsSummary = La siguiente tabla resume los grupos de capacidad en la suscripción {0}. + VolumesSummary = La siguiente tabla resume los volúmenes en la suscripción {0}. + SnapshotPoliciesSummary = La siguiente tabla resume las directivas de instantáneas en la suscripción {0}. + BackupPoliciesSummary = La siguiente tabla resume las directivas de copia de seguridad en la suscripción {0}. + AdConfigIntro = Configuración de Active Directory para la cuenta de NetApp '{0}'. + MountTargetsIntro = Destinos de montaje para el volumen '{0}'. + WarningPoolAllocation = ADVERTENCIA: El grupo de capacidad '{0}' está asignado al {1}% ({2} GiB de {3} GiB). + WarningAdStatus = ADVERTENCIA: La configuración de Active Directory para la cuenta '{0}' tiene el estado '{1}'. + Heading = Azure NetApp Files + AccountsHeading = Cuentas de NetApp + PoolsHeading = Grupos de capacidad + VolumesHeading = Volúmenes + SnapshotPoliciesHeading = Directivas de instantáneas + BackupPoliciesHeading = Directivas de copia de seguridad + ActiveDirectoryHeading = Configuración de Active Directory + EncryptionHeading = Configuración de cifrado + ExportPolicyHeading = Reglas de directiva de exportación + MountTargetsHeading = Destinos de montaje + DataProtectionHeading = Protección de datos + SnapshotsHeading = Instantáneas + QuotaRulesHeading = Reglas de cuota de volumen + Name = Nombre + ResourceGroup = Grupo de recursos + Location = Ubicación + Tags = Etiquetas + Status = Estado + Type = Tipo + Account = Cuenta + Pool = Grupo + Volume = Volumen + ServiceLevel = Nivel de servicio + QosType = Tipo de QoS + SizeTiB = Tamaño (TiB) + SizeGiB = Tamaño (GiB) + QuotaGiB = Cuota (GiB) + AllocatedGiB = Asignado (GiB) + PercentAllocated = % Asignado + VolumeCount = Volúmenes + TotalThroughput = Rendimiento total (MiB/s) + UtilizedThroughput = Rendimiento utilizado (MiB/s) + CoolAccess = Acceso frío + EncryptionType = Tipo de cifrado + EncryptionKeySource = Origen de la clave de cifrado + EncryptionKeyVault = URI de Key Vault + EncryptionKeyName = Nombre de la clave + Protocol = Protocolo + Subnet = Subred delegada + Zone = Zona de disponibilidad + Throughput = Rendimiento (MiB/s) + ActualThroughput = Rendimiento real (MiB/s) + SecurityStyle = Estilo de seguridad + UnixPermission = Permisos de Unix + SnapshotPolicy = Directiva de instantáneas + BackupPolicy = Directiva de copia de seguridad + SnapshotDirVisible = Directorio de instantáneas visible + NetworkFeatures = Características de red + CoolnessPeriod = Período de enfriamiento (días) + TieringPolicy = Directiva de niveles + RetrievalPolicy = Directiva de recuperación + VolumeType = Tipo de volumen + ProvisioningState = Estado de aprovisionamiento + KerberosEnabled = Kerberos + LdapEnabled = LDAP + SmbEncryption = Cifrado SMB + SmbContinuouslyAvailable = SMB Continuously Available + SmbAccessBasedEnumeration = SMB ABE + FileSystemId = ID del sistema de archivos + Domain = Dominio + Username = Nombre de usuario + Site = Sitio AD + OrganizationalUnit = Unidad organizativa + SmbServerName = Nombre del servidor SMB + AesEncryption = Cifrado AES + LdapSigning = Firma LDAP + EncryptDCConnection = Cifrar conexión con DC + AllowLocalNfsUsersWithLdap = Permitir usuarios NFS locales con LDAP + DnsServers = Servidores DNS + Enabled = Habilitado + HourlySchedule = Programación horaria + DailySchedule = Programación diaria + WeeklySchedule = Programación semanal + MonthlySchedule = Programación mensual + SnapshotsToKeep = Instantáneas a conservar + Minute = Minuto + Hour = Hora + Day = Día de la semana + DaysOfMonth = Días del mes + DailyBackups = Copias diarias a conservar + WeeklyBackups = Copias semanales a conservar + MonthlyBackups = Copias mensuales a conservar + RuleIndex = Regla + AllowedClients = Clientes permitidos + UnixReadWrite = NFS Lectura/Escritura + UnixReadOnly = NFS Solo lectura + Nfsv3 = NFSv3 + Nfsv41 = NFSv4.1 + HasRootAccess = Acceso raíz + Kerberos5ReadWrite = Kerberos 5 R/W + Kerberos5iReadWrite = Kerberos 5i R/W + Kerberos5pReadWrite = Kerberos 5p R/W + ChownMode = Modo Chown + IpAddress = Dirección IP + SmbServerFqdn = FQDN del servidor SMB + Created = Creado + None = Ninguno + NoPolicy = Sin directiva asignada + NotConfigured = No configurado + InUse = En uso + PlatformManaged = Administrado por la plataforma + CustomerManaged = Administrado por el cliente + Yes = Yes + No = No +'@ + +# Azure Management Groups (Get-AbrAzManagementGroup) +GetAbrAzManagementGroup = ConvertFrom-StringData @' + InfoLevel = InfoLevel de grupo de administración establecido en {0}. + Collecting = Recopilando información del grupo de administración de Azure. + SectionInfo = Los grupos de administración de Azure proporcionan un ámbito de gobierno por encima de las suscripciones. Todas las suscripciones dentro de un grupo de administración heredan automáticamente las condiciones aplicadas al grupo de administración, lo que permite una política y control de acceso consistentes en toda su patrimonio de Azure. + Heading = Grupos de administración + TableHeading = Grupos de administración + DiagramHeading = Jerarquía del grupo de administración + DiagramAltText = Diagrama de jerarquía del grupo de administración de Azure + DiagramError = No se puede generar el diagrama de jerarquía del grupo de administración: {0}. + Name = Nombre + Id = ID del grupo de administración + ParentName = Grupo principal + ChildGroupCount = Grupos secundarios + SubscriptionCount = Suscripciones + ResourceGroup = Grupo de recursos + Location = Ubicación + NotFound = No se encontraron grupos de administración. + None = Ninguno + ErrorMessage = No se puede recopilar información del grupo de administración: +'@ + +# Azure Private DNS Zones (Get-AbrAzPrivateDnsZone) +GetAbrAzPrivateDnsZone = ConvertFrom-StringData @' + InfoLevel = InfoLevel de zona DNS privada establecido en {0}. + Collecting = Recopilando información de zonas DNS privadas de Azure. + SectionInfo = Las zonas DNS privadas de Azure proporcionan un servicio DNS confiable y seguro para administrar y resolver nombres de dominio en una red virtual sin necesidad de agregar una solución DNS personalizada. Las zonas DNS privadas no son visibles en Internet público y permiten usar nombres de dominio personalizados en lugar de los nombres proporcionados por Azure. + ParagraphDetail = Las siguientes secciones detallan la configuración de las zonas DNS privadas en la suscripción {0}. + ParagraphSummary = La siguiente tabla resume la configuración de las zonas DNS privadas en la suscripción {0}. + Heading = Zonas DNS privadas + TableHeading = Zona DNS privada + Name = Nombre + ResourceGroup = Grupo de recursos + Location = Ubicación + Subscription = Suscripción + SubscriptionID = ID de suscripción + RecordSets = Conjuntos de registros + MaxRecordSets = Máx. conjuntos de registros + VirtualNetworkLinks = Vínculos de red virtual + VNetLinksWithRegistration = Vínculos de red virtual con registro automático + ProvisioningState = Estado de aprovisionamiento + LinkName = Nombre del vínculo + VirtualNetwork = Red virtual + AutoRegistration = Registro automático + VirtualNetworkLinkState = Estado del vínculo + Locks = Bloqueos + Tags = Etiquetas + None = Ninguno + ErrorMessage = No se puede recopilar información de la zona DNS privada: +'@ + +# Azure Virtual Network Gateway (Get-AbrAzVirtualNetworkGateway) +GetAbrAzVirtualNetworkGateway = ConvertFrom-StringData @' + InfoLevel = InfoLevel de puerta de enlace de red virtual establecido en {0}. + Collecting = Recopilando información de puertas de enlace de red virtual de Azure. + SectionInfo = Las puertas de enlace de red virtual de Azure conectan sus redes locales a Azure mediante VPN de sitio a sitio y conectan redes virtuales de Azure entre sí mediante VPN de red virtual a red virtual. Las puertas de enlace de ExpressRoute permiten conexiones privadas y dedicadas a Azure sin atravesar Internet público. + ParagraphDetail = Las siguientes secciones detallan la configuración de las puertas de enlace de red virtual en la suscripción {0}. + ParagraphSummary = La siguiente tabla resume la configuración de las puertas de enlace de red virtual en la suscripción {0}. + Heading = Puertas de enlace de red virtual + TableHeading = Puerta de enlace de red virtual + Name = Nombre + ResourceGroup = Grupo de recursos + Location = Ubicación + Subscription = Suscripción + SubscriptionID = ID de suscripción + VirtualNetwork = Red virtual + GatewayType = Tipo de puerta de enlace + VpnType = Tipo de VPN + SKU = SKU + Generation = Generación + ActiveActive = Activo-Activo + EnableBgp = BGP habilitado + BgpAsn = ASN de BGP + BgpPeeringAddress = Dirección de emparejamiento BGP + ProvisioningState = Estado de aprovisionamiento + Connections = Conexiones + ConnectionName = Nombre + ConnectionType = Tipo de conexión + ConnectionStatus = Estado de conexión + ConnectionProtocol = Protocolo + RoutingWeight = Peso de enrutamiento + NotApplicable = N/D + Locks = Bloqueos + Tags = Etiquetas + None = Ninguno + ErrorMessage = No se puede recopilar información de la puerta de enlace de red virtual: +'@ + +# Azure DDoS Protection Plan (Get-AbrAzDdosProtectionPlan) +GetAbrAzDdosProtectionPlan = ConvertFrom-StringData @' + InfoLevel = InfoLevel del plan de protección DDoS establecido en {0}. + Collecting = Recopilando información de planes de protección DDoS de Azure. + SectionInfo = Los planes de protección DDoS de Azure proporcionan capacidades mejoradas de mitigación de DDoS para todos los recursos de una red virtual. Ofrecen telemetría, alertas y análisis detallados para proteger los recursos de Azure frente a ataques DDoS. + ParagraphDetail = Las siguientes secciones detallan la configuración de los planes de protección DDoS en la suscripción {0}. + ParagraphSummary = La siguiente tabla resume la configuración de los planes de protección DDoS en la suscripción {0}. + Heading = Planes de protección DDoS + TableHeading = Plan de protección DDoS + Name = Nombre + ResourceGroup = Grupo de recursos + Location = Ubicación + Subscription = Suscripción + SubscriptionID = ID de suscripción + ProtectedVirtualNetworks = Redes virtuales protegidas + VirtualNetworkName = Red virtual + ProvisioningState = Estado de aprovisionamiento + Locks = Bloqueos + Tags = Etiquetas + None = Ninguno + ErrorMessage = No se puede recopilar información del plan de protección DDoS: +'@ + +# Azure Application Gateway (Get-AbrAzApplicationGateway) +GetAbrAzApplicationGateway = ConvertFrom-StringData @' + InfoLevel = InfoLevel de puerta de enlace de aplicación establecido en {0}. + Collecting = Recopilando información de puertas de enlace de aplicación de Azure. + SectionInfo = Las puertas de enlace de aplicación de Azure son equilibradores de carga de tráfico web que operan en la capa 7. Admiten terminación SSL/TLS, enrutamiento basado en URL, hospedaje multisitio, afinidad de sesión e integración con el firewall de aplicaciones web. + ParagraphDetail = Las siguientes secciones detallan la configuración de las puertas de enlace de aplicación en la suscripción {0}. + ParagraphSummary = La siguiente tabla resume la configuración de las puertas de enlace de aplicación en la suscripción {0}. + Heading = Puertas de enlace de aplicación + TableHeading = Puerta de enlace de aplicación + Name = Nombre + ResourceGroup = Grupo de recursos + Location = Ubicación + Subscription = Suscripción + SubscriptionID = ID de suscripción + VirtualNetwork = Red virtual + Subnet = Subred + SKU = SKU + Tier = Nivel + Capacity = Capacidad + WafEnabled = WAF habilitado + WafMode = Modo WAF + Http2Enabled = HTTP/2 habilitado + FrontendIPs = IPs de frontend + OperationalState = Estado operativo + ProvisioningState = Estado de aprovisionamiento + Listeners = Agentes de escucha HTTP + ListenerName = Agente de escucha + Protocol = Protocolo + Port = Puerto + HostName = Nombre de host + BackendPools = Grupos de direcciones de backend + PoolName = Nombre del grupo + BackendTargets = Destinos de backend + RoutingRules = Reglas de enrutamiento de solicitudes + RuleName = Nombre de regla + RuleType = Tipo de regla + BackendPool = Grupo de backend + BackendHttpSettings = Configuración HTTP + Unlimited = Ilimitado + NotApplicable = N/D + Tags = Etiquetas + None = Ninguno + ErrorMessage = No se puede recopilar información de la puerta de enlace de aplicación: +'@ + +# Azure Data Collection Rules (Get-AbrAzDataCollectionRule) +GetAbrAzDataCollectionRule = ConvertFrom-StringData @' + InfoLevel = InfoLevel de regla de recopilación de datos establecido en {0}. + Collecting = Recopilando información de reglas de recopilación de datos de Azure. + SectionInfo = Las reglas de recopilación de datos de Azure definen qué datos de supervisión se recopilan, desde dónde y adónde se envían. Especifican orígenes de datos como contadores de rendimiento, registros de eventos de Windows y Syslog, y enrutan esos datos a áreas de trabajo de Log Analytics u otros destinos. + ParagraphDetail = Las siguientes secciones detallan la configuración de las reglas de recopilación de datos en la suscripción {0}. + ParagraphSummary = La siguiente tabla resume la configuración de las reglas de recopilación de datos en la suscripción {0}. + Heading = Reglas de recopilación de datos + TableHeading = Regla de recopilación de datos + Name = Nombre + ResourceGroup = Grupo de recursos + Location = Ubicación + Subscription = Suscripción + SubscriptionID = ID de suscripción + Description = Descripción + DataSources = Orígenes de datos + LogAnalyticsDestinations = Destinos de Log Analytics + ProvisioningState = Estado de aprovisionamiento + PerformanceCounters = Contadores de rendimiento + WindowsEventLogs = Registros de eventos de Windows + Syslog = Syslog + Extensions = Extensiones + LogFiles = Archivos de registro + Destinations = Destinos de Log Analytics + DestinationName = Nombre + WorkspaceId = ID de recurso del área de trabajo + DataFlows = Flujos de datos + Streams = Flujos + Tags = Etiquetas + None = Ninguno + ErrorMessage = No se puede recopilar información de la regla de recopilación de datos: +'@ + +# Azure Public IP Addresses (Get-AbrAzPublicIpAddress) +GetAbrAzPublicIpAddress = ConvertFrom-StringData @' + InfoLevel = InfoLevel de dirección IP pública establecido en {0}. + Collecting = Recopilando información de direcciones IP públicas de Azure. + SectionInfo = Las direcciones IP públicas de Azure proporcionan direcciones IP orientadas a Internet para recursos como máquinas virtuales, equilibradores de carga, puertas de enlace VPN y puertas de enlace de aplicación. Admiten asignación dinámica y estática y están disponibles en SKU Básico y Estándar. + ParagraphDetail = Las siguientes secciones detallan la configuración de las direcciones IP públicas en la suscripción {0}. + ParagraphSummary = La siguiente tabla resume la configuración de las direcciones IP públicas en la suscripción {0}. + Heading = Direcciones IP públicas + TableHeading = Dirección IP pública + Name = Nombre + ResourceGroup = Grupo de recursos + Location = Ubicación + Subscription = Suscripción + SubscriptionID = ID de suscripción + SKU = SKU + Tier = Nivel + IpVersion = Versión de IP + AllocationMethod = Método de asignación + IpAddress = Dirección IP + DnsLabel = Etiqueta DNS + Fqdn = FQDN + Zones = Zonas de disponibilidad + AssociatedResource = Recurso asociado + ProvisioningState = Estado de aprovisionamiento + NotAssigned = No asignado + Tags = Etiquetas + None = Ninguno + ErrorMessage = No se puede recopilar información de dirección IP pública: +'@ + +# Azure Network Watchers (Get-AbrAzNetworkWatcher) +GetAbrAzNetworkWatcher = ConvertFrom-StringData @' + InfoLevel = Nivel de información de NetworkWatcher establecido en {0}. + Collecting = Recopilando información de Azure Network Watcher. + SectionInfo = Azure Network Watcher proporciona capacidades de supervisión y diagnóstico de red por región. Los registros de flujo de NSG capturan información sobre el tráfico IP que fluye a través de los grupos de seguridad de red y, opcionalmente, pueden enrutar datos a un área de trabajo de Log Analytics mediante Traffic Analytics. + ParagraphDetail = Las siguientes secciones detallan la configuración de los monitores de red de la suscripción {0}. + ParagraphSummary = La siguiente tabla resume la configuración de los monitores de red de la suscripción {0}. + Heading = Network Watchers + TableHeading = Network Watcher + Name = Nombre + ResourceGroup = Grupo de recursos + Location = Ubicación + Subscription = Suscripción + SubscriptionID = ID de suscripción + FlowLogs = Registros de flujo + ProvisioningState = Estado de aprovisionamiento + FlowLogsHeading = Registros de flujo de NSG + FlowLogName = Nombre + TargetResource = Recurso de destino + FlowLogEnabled = Habilitado + RetentionDays = Retención (días) + TrafficAnalytics = Traffic Analytics + StorageAccount = Cuenta de almacenamiento + Enabled = Habilitado + Disabled = Deshabilitado + Unlimited = Ilimitado + Tags = Etiquetas + None = Ninguno + ErrorMessage = No se puede recopilar información de Network Watcher: +'@ + +# Azure VM Scale Sets (Get-AbrAzVmScaleSet) +GetAbrAzVmScaleSet = ConvertFrom-StringData @' + InfoLevel = Nivel de información de VmScaleSet establecido en {0}. + Collecting = Recopilando información de conjuntos de escalado de máquinas virtuales de Azure. + SectionInfo = Los conjuntos de escalado de máquinas virtuales (VMSS) de Azure permiten la implementación y administración de un grupo de máquinas virtuales idénticas y con equilibrio de carga. Admiten escalado automático, múltiples zonas de disponibilidad y modos de orquestación flexible o uniforme. + ParagraphDetail = Las siguientes secciones detallan la configuración de los conjuntos de escalado de máquinas virtuales de la suscripción {0}. + ParagraphSummary = La siguiente tabla resume la configuración de los conjuntos de escalado de máquinas virtuales de la suscripción {0}. + Heading = Conjuntos de escalado de VM + TableHeading = Conjunto de escalado de VM + Name = Nombre + ResourceGroup = Grupo de recursos + Location = Ubicación + Subscription = Suscripción + SubscriptionID = ID de suscripción + VmSize = Tamaño de VM + Instances = Instancias + OrchestrationMode = Modo de orquestación + UpgradePolicy = Directiva de actualización + Overprovision = Sobreaprovisionamiento + SinglePlacementGroup = Grupo de selección de ubicación único + Zones = Zonas de disponibilidad + Identity = Identidad + ProvisioningState = Estado de aprovisionamiento + Tags = Etiquetas + None = Ninguno + ErrorMessage = No se puede recopilar información del conjunto de escalado de máquinas virtuales: +'@ + +# Azure Maintenance Configurations (Get-AbrAzMaintenanceConfiguration) +GetAbrAzMaintenanceConfiguration = ConvertFrom-StringData @' + InfoLevel = Nivel de información de MaintenanceConfiguration establecido en {0}. + Collecting = Recopilando información de configuración de mantenimiento de Azure. + SectionInfo = Las configuraciones de mantenimiento de Azure definen ventanas de mantenimiento programadas para los recursos de Azure. Controlan cuándo se aplican las actualizaciones de la plataforma, la aplicación de parches del sistema operativo y otras actividades de mantenimiento, reduciendo el tiempo de inactividad no planificado. + ParagraphDetail = Las siguientes secciones detallan la configuración de las configuraciones de mantenimiento de la suscripción {0}. + ParagraphSummary = La siguiente tabla resume la configuración de las configuraciones de mantenimiento de la suscripción {0}. + Heading = Configuraciones de mantenimiento + TableHeading = Configuración de mantenimiento + Name = Nombre + ResourceGroup = Grupo de recursos + Location = Ubicación + Subscription = Suscripción + SubscriptionID = ID de suscripción + Scope = Ámbito + Visibility = Visibilidad + StartDateTime = Fecha/hora de inicio + ExpirationDateTime = Fecha/hora de expiración + Duration = Duración + RecurEvery = Periodicidad + TimeZone = Zona horaria + NotConfigured = No configurado + NoExpiry = Sin expiración + Tags = Etiquetas + None = Ninguno + ErrorMessage = No se puede recopilar información de la configuración de mantenimiento: +'@ + +# Azure User Assigned Managed Identities (Get-AbrAzUserAssignedManagedIdentity) +GetAbrAzUserAssignedManagedIdentity = ConvertFrom-StringData @' + InfoLevel = Nivel de información de UserAssignedManagedIdentity establecido en {0}. + Collecting = Recopilando información de identidades administradas asignadas por el usuario de Azure. + SectionInfo = Las identidades administradas asignadas por el usuario de Azure son recursos independientes de Azure que proporcionan una identidad de Azure AD para que los servicios se autentiquen en recursos compatibles con la autenticación de Azure Active Directory. Existen independientemente de cualquier servicio o recurso de Azure y pueden asignarse a varios recursos. + ParagraphDetail = Las siguientes secciones detallan la configuración de las identidades administradas asignadas por el usuario en la suscripción {0}. + ParagraphSummary = La siguiente tabla resume la configuración de las identidades administradas asignadas por el usuario en la suscripción {0}. + Heading = Identidades administradas asignadas por el usuario + TableHeading = Identidad administrada asignada por el usuario + Name = Nombre + ResourceGroup = Grupo de recursos + Location = Ubicación + Subscription = Suscripción + SubscriptionID = ID de suscripción + ClientID = ID de cliente + PrincipalID = ID de entidad de seguridad + TenantID = ID de inquilino + Tags = Etiquetas + None = Ninguno + ErrorMessage = No se puede recopilar información de identidades administradas asignadas por el usuario: +'@ + +# Azure Automation Accounts (Get-AbrAzAutomationAccount) +GetAbrAzAutomationAccount = ConvertFrom-StringData @' + InfoLevel = Nivel de información de AutomationAccount establecido en {0}. + Collecting = Recopilando información de cuentas de Automation de Azure. + SectionInfo = Las cuentas de Azure Automation proporcionan automatización y administración de configuración en la nube, con compatibilidad para la automatización de procesos mediante runbooks, administración de configuración y administración de actualizaciones en entornos de Azure y locales. + ParagraphDetail = Las siguientes secciones detallan la configuración de las cuentas de Automation en la suscripción {0}. + ParagraphSummary = La siguiente tabla resume la configuración de las cuentas de Automation en la suscripción {0}. + Heading = Cuentas de Automation + TableHeading = Cuenta de Automation + Name = Nombre + ResourceGroup = Grupo de recursos + Location = Ubicación + Subscription = Suscripción + SubscriptionID = ID de suscripción + State = Estado + RunbooksHeading = Runbooks + RunbookType = Tipo + LastModified = Última modificación + VariablesHeading = Variables + Encrypted = Cifrado + Description = Descripción + SchedulesHeading = Programaciones + Enabled = Habilitado + Frequency = Frecuencia + NextRun = Próxima ejecución + CredentialsHeading = Credenciales + UserName = Nombre de usuario + Yes = Sí + No = No + Tags = Etiquetas + None = Ninguno + ErrorMessage = No se puede recopilar información de cuentas de Automation: +'@ + +# Azure Diagnostic Settings (Get-AbrAzDiagnosticSetting) +GetAbrAzDiagnosticSetting = ConvertFrom-StringData @' + InfoLevel = Nivel de información de DiagnosticSetting establecido en {0}. + Collecting = Recopilando información de configuraciones de diagnóstico de Azure. + SectionInfo = La configuración de diagnóstico de Azure configura la exportación de registros de plataforma y métricas desde recursos de Azure a destinos como áreas de trabajo de Log Analytics, cuentas de almacenamiento y Event Hubs para supervisión, auditoría y análisis. + ParagraphDetail = Las siguientes secciones detallan la configuración de diagnóstico en la suscripción {0}. + ParagraphSummary = La siguiente tabla resume la configuración de diagnóstico en la suscripción {0}. + Heading = Configuraciones de diagnóstico + TableHeading = Configuración de diagnóstico + ResourceName = Nombre del recurso + ResourceType = Tipo de recurso + ResourceGroup = Grupo de recursos + Name = Nombre + Location = Ubicación + Subscription = Suscripción + SubscriptionID = ID de suscripción + LogAnalyticsWorkspace = Área de trabajo de Log Analytics + StorageAccount = Cuenta de almacenamiento + EventHub = Event Hub + LogCategoriesEnabled = Categorías de registro (habilitadas) + MetricsEnabled = Métricas habilitadas + Yes = Sí + No = No + None = Ninguno + ErrorMessage = No se puede recopilar información de configuraciones de diagnóstico: +'@ + +# Azure DNS Forwarding Rulesets (Get-AbrAzDnsForwardingRuleset) +GetAbrAzDnsForwardingRuleset = ConvertFrom-StringData @' + InfoLevel = Nivel de información de DnsForwardingRuleset establecido en {0}. + Collecting = Recopilando información de conjuntos de reglas de reenvío DNS de Azure. + SectionInfo = Los conjuntos de reglas de reenvío DNS de Azure definen conjuntos de reglas de reenvío condicional que dirigen las consultas DNS a servidores DNS específicos. Se asocian con los puntos de conexión de salida del solucionador DNS privado y se vinculan a redes virtuales para controlar el comportamiento de resolución DNS. + ParagraphDetail = Las siguientes secciones detallan la configuración de los conjuntos de reglas de reenvío DNS de la suscripción {0}. + ParagraphSummary = La siguiente tabla resume la configuración de los conjuntos de reglas de reenvío DNS de la suscripción {0}. + Heading = Conjuntos de reglas de reenvío DNS + TableHeading = Conjunto de reglas de reenvío DNS + Name = Nombre + ResourceGroup = Grupo de recursos + Location = Ubicación + Subscription = Suscripción + SubscriptionID = ID de suscripción + ForwardingRules = Reglas de reenvío + VirtualNetworkLinks = Vínculos de red virtual + OutboundEndpoints = Puntos de conexión de salida + ProvisioningState = Estado de aprovisionamiento + ForwardingRulesHeading = Reglas de reenvío + RuleName = Nombre + DomainName = Nombre de dominio + TargetServers = Servidores DNS de destino + RuleState = Estado + VNetLinksHeading = Vínculos de red virtual + LinkName = Nombre + VirtualNetwork = Red virtual + Tags = Etiquetas + None = Ninguno + ErrorMessage = No se puede recopilar información del conjunto de reglas de reenvío DNS: +'@ + +# Azure Network Virtual Appliance (Get-AbrAzNetworkVirtualAppliance) +GetAbrAzNetworkVirtualAppliance = ConvertFrom-StringData @' + InfoLevel = Nivel de información de NetworkVirtualAppliance establecido en {0}. + Collecting = Recopilando información de dispositivos virtuales de red de Azure. + Processing = Procesando el dispositivo virtual de red de Azure '{0}'. + SectionInfo = Los dispositivos virtuales de red (NVA) son productos de red y seguridad de terceros implementados como máquinas virtuales en Azure. Las cargas de trabajo NVA habituales incluyen firewalls de próxima generación, puertas de enlace SD-WAN, optimizadores WAN y controladores de entrega de aplicaciones. Los NVA se identifican por el editor de la imagen de Azure Marketplace y, opcionalmente, por una etiqueta de recurso. Las rutas definidas por el usuario (UDR) con un tipo de próximo salto de Dispositivo virtual se correlacionan para mostrar qué flujos de tráfico se dirigen a través de cada NVA. + ParagraphSummary = La siguiente tabla resume los dispositivos virtuales de red identificados en la suscripción {0}. + ParagraphDetail = Las siguientes secciones detallan la configuración de los dispositivos virtuales de red identificados en la suscripción {0}. + Heading = Dispositivos virtuales de red + TableHeading = Dispositivo virtual de red + TableHeadings = Dispositivos virtuales de red + Name = Nombre + ResourceGroup = Grupo de recursos + Location = Ubicación + Subscription = Suscripción + SubscriptionID = ID de suscripción + Vendor = Proveedor + Publisher = Editor + Offer = Oferta + Sku = SKU + ImageVersion = Versión de la imagen + Status = Estado + Running = En ejecución + Deallocated = Desasignado + Size = Tamaño de VM + PrivateIPAddress = Dirección IP privada + VirtualNetworkSubnet = Red virtual / Subred + NetworkInterfaces = Interfaces de red + DetectedBy = Detectado por + DetectedByPublisher = Editor de Marketplace + DetectedByTag = Etiqueta de recurso + DetectedBoth = Editor de Marketplace y etiqueta de recurso + TagIdentified = NVA identificado por etiqueta + AssociatedRoutes = Rutas UDR asociadas + NoAssociatedRoutes = No se encontraron rutas UDR con un próximo salto de tipo Dispositivo virtual que apunten a este NVA. + RouteTable = Tabla de rutas + RouteName = Nombre de la ruta + AddressPrefix = Prefijo de dirección + NextHopIpAddress = Dirección IP del próximo salto + Tags = Etiquetas + None = Ninguno +'@ + } diff --git a/AsBuiltReport.Microsoft.Azure/Language/fr-FR/MicrosoftAzure.psd1 b/AsBuiltReport.Microsoft.Azure/Language/fr-FR/MicrosoftAzure.psd1 index 37de802..e426793 100644 --- a/AsBuiltReport.Microsoft.Azure/Language/fr-FR/MicrosoftAzure.psd1 +++ b/AsBuiltReport.Microsoft.Azure/Language/fr-FR/MicrosoftAzure.psd1 @@ -11,6 +11,7 @@ InvokeAsBuiltReportMicrosoftAzure = ConvertFrom-StringData @' InfoLevelNotFound = InfoLevel pour '{0}' non trouve. FunctionNotFound = Fonction '{0}' pour la section '{1}' non trouvee. SectionError = Erreur lors du traitement de la section '{0}' : {1}" + AzureApiError = Echec de l'appel API Azure : {0} TenantNotFound = Locataire Azure '{0}' non trouve. TokenAccountIdRequired = L'authentification par jeton Azure necessite le parametre AccountId. Utilisez {0} avec {1} @{{AccountId="utilisateur@domaine.com"}}. ConnectingWithToken = Connexion a Azure par jeton pour le compte {0} dans le locataire {1}. @@ -288,7 +289,7 @@ GetAbrAsrProtectedItems = ConvertFrom-StringData @' InfoLevel = InfoLevel de SiteRecovery defini a {0}. Collecting = Collecte des informations Azure Site Recovery '{0}'. CollectingItems = Collecte des informations des elements proteges Azure Site Recovery. - ParagraghSummary = Les tableaux suivants fournissent des informations sur les elements proteges Azure Site Recovery dans l'abonnement {0}. + ParagraphSummary = Le tableau suivant fournit des informations sur les elements proteges Azure Site Recovery dans l'abonnement {0}. Heading = Elements proteges TableHeading = Elements proteges SubHeading = Site Recovery @@ -301,6 +302,69 @@ GetAbrAsrProtectedItems = ConvertFrom-StringData @' ActiveLocation = Emplacement actif TargetLocation = Emplacement cible FailoverHealth = Etat du basculement + NoTestFailover = Aucun basculement de test n'a été effectué + ParagraphDetail = Les sections suivantes détaillent la configuration des éléments protégés Azure Site Recovery dans l'abonnement {0}. + ReplicationProvider = Fournisseur de réplication + Rpo = RPO (mins) + LastRpoCalculated = Dernier calcul du RPO + LastHeartbeat = Dernier heartbeat + RecoveryVmSize = Taille de la VM de récupération + RecoveryAvailabilityZone = Zone de disponibilité de récupération + NotAvailable = N/D + None = Aucune +'@ + +# Stratégies de réplication Azure Site Recovery (Get-AbrAzAsrPolicy) +GetAbrAzAsrPolicy = ConvertFrom-StringData @' + InfoLevel = Niveau d'information AsrPolicy défini à {0}. + Collecting = Collecte des informations sur les stratégies Azure Site Recovery pour '{0}'. + SectionInfo = Les stratégies de réplication Azure Site Recovery définissent les objectifs de point de récupération (RPO) et l'historique des points de récupération pour les machines virtuelles répliquées. + Heading = Stratégies de réplication + TableHeadings = Stratégies de réplication + ParagraphSummary = Le tableau suivant résume les stratégies de réplication Azure Site Recovery configurées pour le coffre Recovery Services {0}. + ParagraphDetail = Les sections suivantes détaillent les stratégies de réplication Azure Site Recovery configurées pour le coffre Recovery Services {0}. + Name = Nom + Provider = Fournisseur + RpoThreshold = Seuil RPO (mins) + RecoveryPointHistory = Historique des points de récupération (hrs) + AppConsistentFrequency = Instantané cohérent avec l'application (mins) + CrashConsistentFrequency = Instantané cohérent après incident (mins) + MultiVmSync = Synchronisation multi-VM + NotApplicable = N/D +'@ + +# Plans de récupération Azure Site Recovery (Get-AbrAzAsrRecoveryPlan) +GetAbrAzAsrRecoveryPlan = ConvertFrom-StringData @' + InfoLevel = Niveau d'information AsrRecoveryPlan défini à {0}. + Collecting = Collecte des informations sur le plan de récupération Azure Site Recovery pour '{0}'. + SectionInfo = Les plans de récupération Azure Site Recovery orchestrent le basculement et la récupération de groupes de machines virtuelles, permettant des opérations de reprise après sinistre coordonnées. + Heading = Plans de récupération + TableHeadings = Plans de récupération + ParagraphSummary = Le tableau suivant résume les plans de récupération Azure Site Recovery configurés pour le coffre Recovery Services {0}. + ParagraphDetail = Les sections suivantes détaillent les plans de récupération Azure Site Recovery configurés pour le coffre Recovery Services {0}. + Name = Nom + PrimaryFabric = Emplacement principal + RecoveryFabric = Emplacement de récupération + GroupCount = Groupes + ProtectedItemCount = Éléments protégés + FailoverDeploymentModel = Modèle de déploiement de basculement + None = Aucun +'@ + +# Mappages réseau Azure Site Recovery (Get-AbrAzAsrNetworkMapping) +GetAbrAzAsrNetworkMapping = ConvertFrom-StringData @' + InfoLevel = Niveau d'information AsrNetworkMapping défini à {0}. + Collecting = Collecte des informations de mappage réseau Azure Site Recovery pour '{0}'. + SectionInfo = Les mappages réseau Azure Site Recovery définissent la relation entre les réseaux virtuels source et cible utilisés lors des opérations de basculement. + Heading = Mappages réseau + TableHeadings = Mappages réseau + ParagraphSummary = Le tableau suivant résume les mappages réseau Azure Site Recovery configurés pour le coffre Recovery Services {0}. + ParagraphDetail = Les sections suivantes détaillent les mappages réseau Azure Site Recovery configurés pour le coffre Recovery Services {0}. + Name = Nom + PrimaryNetwork = Réseau principal + RecoveryNetwork = Réseau de récupération + MappingState = État du mappage + None = Aucun '@ # Azure Availability Sets (Get-AbrAzAvailabilitySet) @@ -422,6 +486,7 @@ GetAbrAzStorageAccount = ConvertFrom-StringData @' Disabled = Desactive Unknown = Inconnu Created = Cree + Locks = Verrous Tags = Balises None = Aucun '@ @@ -484,6 +549,7 @@ GetAbrAzFirewall = ConvertFrom-StringData @' NatRules = Regles NAT NetworkRules = Regles reseau AppRules = Regles d'application + Locks = Verrous Tags = Balises None = Aucun '@ @@ -592,6 +658,7 @@ GetAbrAzKeyVault = ConvertFrom-StringData @' Disabled = Desactive NoAccessEnabled = Aucun acces active EnabledDays = Active ({0} jours) + Locks = Verrous Tags = Balises None = Aucun days = jours @@ -665,7 +732,7 @@ GetAbrAzLoadBalancer = ConvertFrom-StringData @' Heading = Equilibreurs de charge TableHeading = Equilibreur de charge TableHeadings = Equilibreurs de charge - LoadBalancerImage = Image de l'equilibreur de charge + Image = Image de l'equilibreur de charge ImageError = Impossible d'afficher l'image de l'equilibreur de charge Name = Nom ResourceGroup = Groupe de ressources @@ -715,6 +782,7 @@ GetAbrAzLogAnalyticsWorkspace = ConvertFrom-StringData @' Disabled = Desactive Unknown = Inconnu NoQuota = Aucun quota defini + Locks = Verrous Tags = Balises None = Aucun '@ @@ -859,6 +927,13 @@ GetAbrAzRecoveryServicesVault = ConvertFrom-StringData @' ProvisioningState = Etat de provisionnement PrivateEndpointStateForBackup = Etat du point de terminaison prive pour la sauvegarde PrivateEndpointStateForSiteRecovery = Etat du point de terminaison prive pour Site Recovery + StorageRedundancy = Redondance du stockage + CrossRegionRestore = Restauration interrégionale + SoftDeleteState = État de suppression réversible + SoftDeleteRetentionDays = Rétention de suppression réversible (jours) + ImmutabilityState = État d'immuabilité + PublicNetworkAccess = Accès réseau public + Locks = Verrous Tags = Balises None = Aucun '@ @@ -883,6 +958,7 @@ GetAbrAzRouteTable = ConvertFrom-StringData @' AddressPrefix = Prefixe d'adresse NextHopType = Type de prochain troncon NextHopIpAddress = Adresse IP du prochain troncon + Locks = Verrous Tags = Balises None = Aucun '@ @@ -1063,6 +1139,7 @@ GetAbrAzVirtualNetwork = ConvertFrom-StringData @' Subnets = Sous-reseaux DnsServers = Serveurs DNS Default = Par defaut (fourni par Azure) + Locks = Verrous Tags = Balises None = Aucun '@ @@ -1254,4 +1331,588 @@ GetAbrAzDesktopVirtualization = ConvertFrom-StringData @' Allowed = Autorise '@ + +# Azure NetApp Files (Get-AbrAzNetAppFiles) +GetAbrAzNetAppFiles = ConvertFrom-StringData @' + InfoLevel = InfoLevel NetAppFiles defini sur {0}. + Collecting = Collecte des informations Azure NetApp Files. + SectionInfo = Azure NetApp Files est un service de stockage de fichiers mesure, hautes performances, de classe entreprise s'executant sur Azure. Il prend en charge SMB, NFSv3, NFSv4.1 et les volumes a double protocole avec instantanes integres, replication inter-regions et sauvegarde. + AccountsSummary = Le tableau suivant resume les comptes NetApp Files dans l'abonnement {0}. + PoolsSummary = Le tableau suivant resume les pools de capacite dans l'abonnement {0}. + VolumesSummary = Le tableau suivant resume les volumes dans l'abonnement {0}. + SnapshotPoliciesSummary = Le tableau suivant resume les strategies d'instantanes dans l'abonnement {0}. + BackupPoliciesSummary = Le tableau suivant resume les strategies de sauvegarde dans l'abonnement {0}. + AdConfigIntro = Configuration Active Directory pour le compte NetApp '{0}'. + MountTargetsIntro = Cibles de montage pour le volume '{0}'. + WarningPoolAllocation = AVERTISSEMENT: Le pool de capacite '{0}' est alloue a {1}% ({2} GiB sur {3} GiB). + WarningAdStatus = AVERTISSEMENT: La configuration Active Directory pour le compte '{0}' a le statut '{1}'. + Heading = Azure NetApp Files + AccountsHeading = Comptes NetApp + PoolsHeading = Pools de capacite + VolumesHeading = Volumes + SnapshotPoliciesHeading = Strategies d'instantanes + BackupPoliciesHeading = Strategies de sauvegarde + ActiveDirectoryHeading = Configuration Active Directory + EncryptionHeading = Configuration du chiffrement + ExportPolicyHeading = Regles de strategie d'exportation + MountTargetsHeading = Cibles de montage + DataProtectionHeading = Protection des donnees + SnapshotsHeading = Instantanes + QuotaRulesHeading = Regles de quota de volume + Name = Nom + ResourceGroup = Groupe de ressources + Location = Emplacement + Tags = Balises + Status = Statut + Type = Type + Account = Compte + Pool = Pool + Volume = Volume + ServiceLevel = Niveau de service + QosType = Type QoS + SizeTiB = Taille (TiB) + SizeGiB = Taille (GiB) + QuotaGiB = Quota (GiB) + AllocatedGiB = Alloue (GiB) + PercentAllocated = % Alloue + VolumeCount = Volumes + TotalThroughput = Debit total (MiB/s) + UtilizedThroughput = Debit utilise (MiB/s) + CoolAccess = Acces froid + EncryptionType = Type de chiffrement + EncryptionKeySource = Source de la cle de chiffrement + EncryptionKeyVault = URI Key Vault + EncryptionKeyName = Nom de la cle + Protocol = Protocole + Subnet = Sous-reseau delegue + Zone = Zone de disponibilite + Throughput = Debit (MiB/s) + ActualThroughput = Debit reel (MiB/s) + SecurityStyle = Style de securite + UnixPermission = Autorisations Unix + SnapshotPolicy = Strategie d'instantanes + BackupPolicy = Strategie de sauvegarde + SnapshotDirVisible = Repertoire d'instantanes visible + NetworkFeatures = Fonctionnalites reseau + CoolnessPeriod = Periode de refroidissement (jours) + TieringPolicy = Strategie de hierarchisation + RetrievalPolicy = Strategie de recuperation + VolumeType = Type de volume + ProvisioningState = Etat de provisionnement + KerberosEnabled = Kerberos + LdapEnabled = LDAP + SmbEncryption = Chiffrement SMB + SmbContinuouslyAvailable = SMB Continuously Available + SmbAccessBasedEnumeration = SMB ABE + FileSystemId = ID du systeme de fichiers + Domain = Domaine + Username = Nom d'utilisateur + Site = Site AD + OrganizationalUnit = Unite d'organisation + SmbServerName = Nom du serveur SMB + AesEncryption = Chiffrement AES + LdapSigning = Signature LDAP + EncryptDCConnection = Chiffrer la connexion DC + AllowLocalNfsUsersWithLdap = Autoriser les utilisateurs NFS locaux avec LDAP + DnsServers = Serveurs DNS + Enabled = Active + HourlySchedule = Planification horaire + DailySchedule = Planification quotidienne + WeeklySchedule = Planification hebdomadaire + MonthlySchedule = Planification mensuelle + SnapshotsToKeep = Instantanes a conserver + Minute = Minute + Hour = Heure + Day = Jour de la semaine + DaysOfMonth = Jours du mois + DailyBackups = Sauvegardes quotidiennes a conserver + WeeklyBackups = Sauvegardes hebdomadaires a conserver + MonthlyBackups = Sauvegardes mensuelles a conserver + RuleIndex = Regle + AllowedClients = Clients autorises + UnixReadWrite = NFS Lecture/Ecriture + UnixReadOnly = NFS Lecture seule + Nfsv3 = NFSv3 + Nfsv41 = NFSv4.1 + HasRootAccess = Acces racine + Kerberos5ReadWrite = Kerberos 5 R/W + Kerberos5iReadWrite = Kerberos 5i R/W + Kerberos5pReadWrite = Kerberos 5p R/W + ChownMode = Mode Chown + IpAddress = Adresse IP + SmbServerFqdn = FQDN du serveur SMB + Created = Cree + None = Aucun + NoPolicy = Aucune strategie attachee + NotConfigured = Non configure + InUse = Utilise + PlatformManaged = Geree par la plateforme + CustomerManaged = Geree par le client + Yes = Yes + No = No +'@ + +# Azure Management Groups (Get-AbrAzManagementGroup) +GetAbrAzManagementGroup = ConvertFrom-StringData @' + InfoLevel = InfoLevel du groupe de gestion defini a {0}. + Collecting = Collecte des informations du groupe de gestion Azure. + SectionInfo = Les groupes de gestion Azure fournissent une etendue de gouvernance au-dessus des abonnements. Tous les abonnements au sein d'un groupe de gestion heritent automatiquement des conditions appliquees au groupe de gestion, permettant une politique et un controle d'acces coherents dans l'ensemble de votre patrimoine Azure. + Heading = Groupes de gestion + TableHeading = Groupes de gestion + DiagramHeading = Hierarchie du groupe de gestion + DiagramAltText = Diagramme de hierarchie du groupe de gestion Azure + DiagramError = Impossible de generer le diagramme de hierarchie du groupe de gestion : {0}. + Name = Nom + Id = ID du groupe de gestion + ParentName = Groupe parent + ChildGroupCount = Groupes enfants + SubscriptionCount = Abonnements + ResourceGroup = Groupe de ressources + Location = Emplacement + NotFound = Aucun groupe de gestion trouve. + None = Aucun + ErrorMessage = Impossible de collecter les informations du groupe de gestion: +'@ + +# Azure Private DNS Zones (Get-AbrAzPrivateDnsZone) +GetAbrAzPrivateDnsZone = ConvertFrom-StringData @' + InfoLevel = InfoLevel de zone DNS privee defini a {0}. + Collecting = Collecte des informations de zone DNS privee Azure. + SectionInfo = Les zones DNS privees Azure fournissent un service DNS fiable et securise pour gerer et resoudre les noms de domaine dans un reseau virtuel sans avoir besoin d'ajouter une solution DNS personnalisee. Les zones DNS privees ne sont pas visibles sur Internet et permettent d'utiliser des noms de domaine personnalises plutot que les noms fournis par Azure. + ParagraphDetail = Les sections suivantes detaillent la configuration des zones DNS privees dans l'abonnement {0}. + ParagraphSummary = Le tableau suivant resume la configuration des zones DNS privees dans l'abonnement {0}. + Heading = Zones DNS privees + TableHeading = Zone DNS privee + Name = Nom + ResourceGroup = Groupe de ressources + Location = Emplacement + Subscription = Abonnement + SubscriptionID = ID d'abonnement + RecordSets = Jeux d'enregistrements + MaxRecordSets = Max. jeux d'enregistrements + VirtualNetworkLinks = Liens de reseau virtuel + VNetLinksWithRegistration = Liens de reseau virtuel avec enregistrement automatique + ProvisioningState = Etat d'approvisionnement + LinkName = Nom du lien + VirtualNetwork = Reseau virtuel + AutoRegistration = Enregistrement automatique + VirtualNetworkLinkState = Etat du lien + Locks = Verrous + Tags = Balises + None = Aucun + ErrorMessage = Impossible de collecter les informations de zone DNS privee: +'@ + +# Azure Virtual Network Gateway (Get-AbrAzVirtualNetworkGateway) +GetAbrAzVirtualNetworkGateway = ConvertFrom-StringData @' + InfoLevel = InfoLevel de passerelle de reseau virtuel defini a {0}. + Collecting = Collecte des informations de passerelle de reseau virtuel Azure. + SectionInfo = Les passerelles de reseau virtuel Azure connectent vos reseaux locaux a Azure via des VPN de site a site et connectent des reseaux virtuels Azure entre eux via des VPN de reseau virtuel a reseau virtuel. Les passerelles ExpressRoute permettent des connexions privees et dediees a Azure sans traverser Internet. + ParagraphDetail = Les sections suivantes detaillent la configuration des passerelles de reseau virtuel dans l'abonnement {0}. + ParagraphSummary = Le tableau suivant resume la configuration des passerelles de reseau virtuel dans l'abonnement {0}. + Heading = Passerelles de reseau virtuel + TableHeading = Passerelle de reseau virtuel + Name = Nom + ResourceGroup = Groupe de ressources + Location = Emplacement + Subscription = Abonnement + SubscriptionID = ID d'abonnement + VirtualNetwork = Reseau virtuel + GatewayType = Type de passerelle + VpnType = Type de VPN + SKU = SKU + Generation = Generation + ActiveActive = Actif-Actif + EnableBgp = BGP active + BgpAsn = ASN BGP + BgpPeeringAddress = Adresse de peering BGP + ProvisioningState = Etat d'approvisionnement + Connections = Connexions + ConnectionName = Nom + ConnectionType = Type de connexion + ConnectionStatus = Etat de connexion + ConnectionProtocol = Protocole + RoutingWeight = Poids de routage + NotApplicable = S/O + Locks = Verrous + Tags = Balises + None = Aucun + ErrorMessage = Impossible de collecter les informations de passerelle de reseau virtuel: +'@ + +# Azure DDoS Protection Plan (Get-AbrAzDdosProtectionPlan) +GetAbrAzDdosProtectionPlan = ConvertFrom-StringData @' + InfoLevel = InfoLevel du plan de protection DDoS defini a {0}. + Collecting = Collecte des informations de plan de protection DDoS Azure. + SectionInfo = Les plans de protection DDoS Azure fournissent des capacites de mitigation DDoS ameliorees pour toutes les ressources d'un reseau virtuel. Ils offrent la telemetrie, des alertes et des analyses detaillees pour proteger les ressources Azure contre les attaques DDoS. + ParagraphDetail = Les sections suivantes detaillent la configuration des plans de protection DDoS dans l'abonnement {0}. + ParagraphSummary = Le tableau suivant resume la configuration des plans de protection DDoS dans l'abonnement {0}. + Heading = Plans de protection DDoS + TableHeading = Plan de protection DDoS + Name = Nom + ResourceGroup = Groupe de ressources + Location = Emplacement + Subscription = Abonnement + SubscriptionID = ID d'abonnement + ProtectedVirtualNetworks = Reseaux virtuels proteges + VirtualNetworkName = Reseau virtuel + ProvisioningState = Etat d'approvisionnement + Locks = Verrous + Tags = Balises + None = Aucun + ErrorMessage = Impossible de collecter les informations de plan de protection DDoS: +'@ + +# Azure Application Gateway (Get-AbrAzApplicationGateway) +GetAbrAzApplicationGateway = ConvertFrom-StringData @' + InfoLevel = InfoLevel de passerelle d'application defini a {0}. + Collecting = Collecte des informations de passerelle d'application Azure. + SectionInfo = Les passerelles d'application Azure sont des equilibreurs de charge de trafic web qui operent au niveau de la couche 7. Elles prennent en charge la terminaison SSL/TLS, le routage base sur les URL, l'hebergement multisites, l'affinite de session et l'integration du pare-feu d'applications web. + ParagraphDetail = Les sections suivantes detaillent la configuration des passerelles d'application dans l'abonnement {0}. + ParagraphSummary = Le tableau suivant resume la configuration des passerelles d'application dans l'abonnement {0}. + Heading = Passerelles d'application + TableHeading = Passerelle d'application + Name = Nom + ResourceGroup = Groupe de ressources + Location = Emplacement + Subscription = Abonnement + SubscriptionID = ID d'abonnement + VirtualNetwork = Reseau virtuel + Subnet = Sous-reseau + SKU = SKU + Tier = Niveau + Capacity = Capacite + WafEnabled = WAF active + WafMode = Mode WAF + Http2Enabled = HTTP/2 active + FrontendIPs = IPs frontend + OperationalState = Etat operationnel + ProvisioningState = Etat d'approvisionnement + Listeners = Ecouteurs HTTP + ListenerName = Ecouteur + Protocol = Protocole + Port = Port + HostName = Nom d'hote + BackendPools = Pools d'adresses backend + PoolName = Nom du pool + BackendTargets = Cibles backend + RoutingRules = Regles de routage des requetes + RuleName = Nom de regle + RuleType = Type de regle + BackendPool = Pool backend + BackendHttpSettings = Parametres HTTP + Unlimited = Illimite + NotApplicable = S/O + Tags = Balises + None = Aucun + ErrorMessage = Impossible de collecter les informations de passerelle d'application: +'@ + +# Azure Data Collection Rules (Get-AbrAzDataCollectionRule) +GetAbrAzDataCollectionRule = ConvertFrom-StringData @' + InfoLevel = InfoLevel de regle de collecte de donnees defini a {0}. + Collecting = Collecte des informations de regle de collecte de donnees Azure. + SectionInfo = Les regles de collecte de donnees Azure definissent quelles donnees de surveillance collecter, d'ou elles proviennent et ou les envoyer. Elles specifient des sources de donnees telles que les compteurs de performances, les journaux d'evenements Windows et Syslog, et acheminent ces donnees vers des espaces de travail Log Analytics ou d'autres destinations. + ParagraphDetail = Les sections suivantes detaillent la configuration des regles de collecte de donnees dans l'abonnement {0}. + ParagraphSummary = Le tableau suivant resume la configuration des regles de collecte de donnees dans l'abonnement {0}. + Heading = Regles de collecte de donnees + TableHeading = Regle de collecte de donnees + Name = Nom + ResourceGroup = Groupe de ressources + Location = Emplacement + Subscription = Abonnement + SubscriptionID = ID d'abonnement + Description = Description + DataSources = Sources de donnees + LogAnalyticsDestinations = Destinations Log Analytics + ProvisioningState = Etat d'approvisionnement + PerformanceCounters = Compteurs de performances + WindowsEventLogs = Journaux d'evenements Windows + Syslog = Syslog + Extensions = Extensions + LogFiles = Fichiers journaux + Destinations = Destinations Log Analytics + DestinationName = Nom + WorkspaceId = ID de ressource de l'espace de travail + DataFlows = Flux de donnees + Streams = Flux + Tags = Balises + None = Aucun + ErrorMessage = Impossible de collecter les informations de regle de collecte de donnees: +'@ + +# Azure Public IP Addresses (Get-AbrAzPublicIpAddress) +GetAbrAzPublicIpAddress = ConvertFrom-StringData @' + InfoLevel = InfoLevel d'adresse IP publique defini a {0}. + Collecting = Collecte des informations d'adresse IP publique Azure. + SectionInfo = Les adresses IP publiques Azure fournissent des adresses IP accessibles depuis Internet pour des ressources telles que les machines virtuelles, les equilibreurs de charge, les passerelles VPN et les passerelles d'application. Elles prennent en charge l'allocation dynamique et statique et sont disponibles dans les SKU De base et Standard. + ParagraphDetail = Les sections suivantes detaillent la configuration des adresses IP publiques dans l'abonnement {0}. + ParagraphSummary = Le tableau suivant resume la configuration des adresses IP publiques dans l'abonnement {0}. + Heading = Adresses IP publiques + TableHeading = Adresse IP publique + Name = Nom + ResourceGroup = Groupe de ressources + Location = Emplacement + Subscription = Abonnement + SubscriptionID = ID d'abonnement + SKU = SKU + Tier = Niveau + IpVersion = Version IP + AllocationMethod = Methode d'allocation + IpAddress = Adresse IP + DnsLabel = Etiquette DNS + Fqdn = FQDN + Zones = Zones de disponibilite + AssociatedResource = Ressource associee + ProvisioningState = Etat d'approvisionnement + NotAssigned = Non attribuee + Tags = Balises + None = Aucun + ErrorMessage = Impossible de collecter les informations d'adresse IP publique: +'@ + +# Azure Network Watchers (Get-AbrAzNetworkWatcher) +GetAbrAzNetworkWatcher = ConvertFrom-StringData @' + InfoLevel = Niveau d'information NetworkWatcher defini sur {0}. + Collecting = Collecte des informations Azure Network Watcher. + SectionInfo = Azure Network Watcher fournit des capacites de surveillance et de diagnostic reseau par region. Les journaux de flux NSG capturent des informations sur le trafic IP traversant les groupes de securite reseau et peuvent optionnellement acheminer les donnees vers un espace de travail Log Analytics via Traffic Analytics. + ParagraphDetail = Les sections suivantes detaillent la configuration des moniteurs reseau de l'abonnement {0}. + ParagraphSummary = Le tableau suivant resume la configuration des moniteurs reseau de l'abonnement {0}. + Heading = Network Watchers + TableHeading = Network Watcher + Name = Nom + ResourceGroup = Groupe de ressources + Location = Emplacement + Subscription = Abonnement + SubscriptionID = ID d'abonnement + FlowLogs = Journaux de flux + ProvisioningState = Etat d'approvisionnement + FlowLogsHeading = Journaux de flux NSG + FlowLogName = Nom + TargetResource = Ressource cible + FlowLogEnabled = Actif + RetentionDays = Retention (jours) + TrafficAnalytics = Traffic Analytics + StorageAccount = Compte de stockage + Enabled = Actif + Disabled = Inactif + Unlimited = Illimite + Tags = Balises + None = Aucun + ErrorMessage = Impossible de collecter les informations de Network Watcher: +'@ + +# Azure VM Scale Sets (Get-AbrAzVmScaleSet) +GetAbrAzVmScaleSet = ConvertFrom-StringData @' + InfoLevel = Niveau d'information VmScaleSet defini sur {0}. + Collecting = Collecte des informations sur les groupes de machines virtuelles identiques Azure. + SectionInfo = Les groupes de machines virtuelles identiques (VMSS) Azure permettent le deploiement et la gestion d'un groupe de machines virtuelles identiques et a charge equilibree. Ils prennent en charge la mise a l'echelle automatique, plusieurs zones de disponibilite et les modes d'orchestration flexible ou uniforme. + ParagraphDetail = Les sections suivantes detaillent la configuration des groupes de machines virtuelles identiques de l'abonnement {0}. + ParagraphSummary = Le tableau suivant resume la configuration des groupes de machines virtuelles identiques de l'abonnement {0}. + Heading = Groupes de machines virtuelles identiques + TableHeading = Groupe de machines virtuelles identiques + Name = Nom + ResourceGroup = Groupe de ressources + Location = Emplacement + Subscription = Abonnement + SubscriptionID = ID d'abonnement + VmSize = Taille de VM + Instances = Instances + OrchestrationMode = Mode d'orchestration + UpgradePolicy = Strategie de mise a niveau + Overprovision = Surprovisionnement + SinglePlacementGroup = Groupe de placement unique + Zones = Zones de disponibilite + Identity = Identite + ProvisioningState = Etat d'approvisionnement + Tags = Balises + None = Aucun + ErrorMessage = Impossible de collecter les informations des groupes de machines virtuelles identiques: +'@ + +# Azure Maintenance Configurations (Get-AbrAzMaintenanceConfiguration) +GetAbrAzMaintenanceConfiguration = ConvertFrom-StringData @' + InfoLevel = Niveau d'information MaintenanceConfiguration defini sur {0}. + Collecting = Collecte des informations de configuration de maintenance Azure. + SectionInfo = Les configurations de maintenance Azure definissent des fenetres de maintenance planifiees pour les ressources Azure. Elles controlent le moment ou les mises a jour de la plateforme, l'application des correctifs du systeme d'exploitation et d'autres activites de maintenance sont appliquees, reduisant ainsi les temps d'arret non planifies. + ParagraphDetail = Les sections suivantes detaillent la configuration des configurations de maintenance de l'abonnement {0}. + ParagraphSummary = Le tableau suivant resume la configuration des configurations de maintenance de l'abonnement {0}. + Heading = Configurations de maintenance + TableHeading = Configuration de maintenance + Name = Nom + ResourceGroup = Groupe de ressources + Location = Emplacement + Subscription = Abonnement + SubscriptionID = ID d'abonnement + Scope = Portee + Visibility = Visibilite + StartDateTime = Date/heure de debut + ExpirationDateTime = Date/heure d'expiration + Duration = Duree + RecurEvery = Periodicite + TimeZone = Fuseau horaire + NotConfigured = Non configure + NoExpiry = Sans expiration + Tags = Balises + None = Aucun + ErrorMessage = Impossible de collecter les informations de configuration de maintenance: +'@ + +# Azure User Assigned Managed Identities (Get-AbrAzUserAssignedManagedIdentity) +GetAbrAzUserAssignedManagedIdentity = ConvertFrom-StringData @' + InfoLevel = Niveau d'information UserAssignedManagedIdentity defini sur {0}. + Collecting = Collecte des informations sur les identites managees affectees par l'utilisateur Azure. + SectionInfo = Les identites managees affectees par l'utilisateur Azure sont des ressources Azure autonomes qui fournissent une identite Azure AD pour les services qui s'authentifient aupres de ressources prenant en charge l'authentification Azure Active Directory. Elles existent independamment de tout service ou ressource Azure et peuvent etre affectees a plusieurs ressources. + ParagraphDetail = Les sections suivantes detaillent la configuration des identites managees affectees par l'utilisateur de l'abonnement {0}. + ParagraphSummary = Le tableau suivant resume la configuration des identites managees affectees par l'utilisateur de l'abonnement {0}. + Heading = Identites managees affectees par l'utilisateur + TableHeading = Identite managee affectee par l'utilisateur + Name = Nom + ResourceGroup = Groupe de ressources + Location = Emplacement + Subscription = Abonnement + SubscriptionID = ID d'abonnement + ClientID = ID client + PrincipalID = ID du principal + TenantID = ID du locataire + Tags = Balises + None = Aucun + ErrorMessage = Impossible de collecter les informations sur les identites managees affectees par l'utilisateur: +'@ + +# Azure Automation Accounts (Get-AbrAzAutomationAccount) +GetAbrAzAutomationAccount = ConvertFrom-StringData @' + InfoLevel = Niveau d'information AutomationAccount defini sur {0}. + Collecting = Collecte des informations sur les comptes Azure Automation. + SectionInfo = Les comptes Azure Automation fournissent l'automatisation et la gestion de la configuration dans le cloud, avec prise en charge de l'automatisation des processus via des runbooks, la gestion de la configuration et la gestion des mises a jour dans les environnements Azure et locaux. + ParagraphDetail = Les sections suivantes detaillent la configuration des comptes Automation de l'abonnement {0}. + ParagraphSummary = Le tableau suivant resume la configuration des comptes Automation de l'abonnement {0}. + Heading = Comptes Automation + TableHeading = Compte Automation + Name = Nom + ResourceGroup = Groupe de ressources + Location = Emplacement + Subscription = Abonnement + SubscriptionID = ID d'abonnement + State = Etat + RunbooksHeading = Runbooks + RunbookType = Type + LastModified = Derniere modification + VariablesHeading = Variables + Encrypted = Chiffre + Description = Description + SchedulesHeading = Planifications + Enabled = Active + Frequency = Frequence + NextRun = Prochaine execution + CredentialsHeading = Informations d'identification + UserName = Nom d'utilisateur + Yes = Oui + No = Non + Tags = Balises + None = Aucun + ErrorMessage = Impossible de collecter les informations sur les comptes Automation: +'@ + +# Azure Diagnostic Settings (Get-AbrAzDiagnosticSetting) +GetAbrAzDiagnosticSetting = ConvertFrom-StringData @' + InfoLevel = Niveau d'information DiagnosticSetting defini sur {0}. + Collecting = Collecte des informations sur les parametres de diagnostic Azure. + SectionInfo = Les parametres de diagnostic Azure configurent l'exportation des journaux de plateforme et des metriques depuis les ressources Azure vers des destinations telles que les espaces de travail Log Analytics, les comptes de stockage et les Event Hubs pour la surveillance, l'audit et l'analyse. + ParagraphDetail = Les sections suivantes detaillent la configuration des parametres de diagnostic de l'abonnement {0}. + ParagraphSummary = Le tableau suivant resume la configuration des parametres de diagnostic de l'abonnement {0}. + Heading = Parametres de diagnostic + TableHeading = Parametre de diagnostic + ResourceName = Nom de la ressource + ResourceType = Type de ressource + ResourceGroup = Groupe de ressources + Name = Nom + Location = Emplacement + Subscription = Abonnement + SubscriptionID = ID d'abonnement + LogAnalyticsWorkspace = Espace de travail Log Analytics + StorageAccount = Compte de stockage + EventHub = Event Hub + LogCategoriesEnabled = Categories de journaux (activees) + MetricsEnabled = Metriques activees + Yes = Oui + No = Non + None = Aucun + ErrorMessage = Impossible de collecter les informations sur les parametres de diagnostic: +'@ + +# Azure DNS Forwarding Rulesets (Get-AbrAzDnsForwardingRuleset) +GetAbrAzDnsForwardingRuleset = ConvertFrom-StringData @' + InfoLevel = Niveau d'information DnsForwardingRuleset defini sur {0}. + Collecting = Collecte des informations sur les ensembles de regles de transfert DNS Azure. + SectionInfo = Les ensembles de regles de transfert DNS Azure definissent des ensembles de regles de transfert conditionnel qui dirigent les requetes DNS vers des serveurs DNS specifiques. Ils sont associes aux points de terminaison sortants du resolveur DNS prive et lies aux reseaux virtuels pour controler le comportement de resolution DNS. + ParagraphDetail = Les sections suivantes detaillent la configuration des ensembles de regles de transfert DNS de l'abonnement {0}. + ParagraphSummary = Le tableau suivant resume la configuration des ensembles de regles de transfert DNS de l'abonnement {0}. + Heading = Ensembles de regles de transfert DNS + TableHeading = Ensemble de regles de transfert DNS + Name = Nom + ResourceGroup = Groupe de ressources + Location = Emplacement + Subscription = Abonnement + SubscriptionID = ID d'abonnement + ForwardingRules = Regles de transfert + VirtualNetworkLinks = Liens de reseau virtuel + OutboundEndpoints = Points de terminaison sortants + ProvisioningState = Etat d'approvisionnement + ForwardingRulesHeading = Regles de transfert + RuleName = Nom + DomainName = Nom de domaine + TargetServers = Serveurs DNS cibles + RuleState = Etat + VNetLinksHeading = Liens de reseau virtuel + LinkName = Nom + VirtualNetwork = Reseau virtuel + Tags = Balises + None = Aucun + ErrorMessage = Impossible de collecter les informations des ensembles de regles de transfert DNS: +'@ + +# Azure Network Virtual Appliance (Get-AbrAzNetworkVirtualAppliance) +GetAbrAzNetworkVirtualAppliance = ConvertFrom-StringData @' + InfoLevel = Niveau d'information NetworkVirtualAppliance defini sur {0}. + Collecting = Collecte des informations sur les appliances virtuelles reseau Azure. + Processing = Traitement de l'appliance virtuelle reseau Azure '{0}'. + SectionInfo = Les appliances virtuelles reseau (NVA) sont des produits reseau et de securite tiers deployes sous forme de machines virtuelles dans Azure. Les charges de travail NVA courantes incluent les pare-feux nouvelle generation, les passerelles SD-WAN, les optimiseurs WAN et les controleurs de distribution d'applications. Les NVA sont identifiees par leur editeur d'image Marketplace Azure et, eventuellement, par une balise de ressource. Les routes definies par l'utilisateur (UDR) dont le type de prochain troncon est Appliance virtuelle sont mises en correspondance pour indiquer quels flux de trafic sont diriges via chaque NVA. + ParagraphSummary = Le tableau suivant resume les appliances virtuelles reseau identifiees dans l'abonnement {0}. + ParagraphDetail = Les sections suivantes detaillent la configuration des appliances virtuelles reseau identifiees dans l'abonnement {0}. + Heading = Appliances virtuelles reseau + TableHeading = Appliance virtuelle reseau + TableHeadings = Appliances virtuelles reseau + Name = Nom + ResourceGroup = Groupe de ressources + Location = Emplacement + Subscription = Abonnement + SubscriptionID = ID d'abonnement + Vendor = Fournisseur + Publisher = Editeur + Offer = Offre + Sku = SKU + ImageVersion = Version de l'image + Status = Statut + Running = En cours d'execution + Deallocated = Desallouee + Size = Taille de la VM + PrivateIPAddress = Adresse IP privee + VirtualNetworkSubnet = Reseau virtuel / Sous-reseau + NetworkInterfaces = Interfaces reseau + DetectedBy = Detectee par + DetectedByPublisher = Editeur Marketplace + DetectedByTag = Balise de ressource + DetectedBoth = Editeur Marketplace et balise de ressource + TagIdentified = NVA identifiee par balise + AssociatedRoutes = Routes UDR associees + NoAssociatedRoutes = Aucune route UDR avec un prochain troncon de type Appliance virtuelle n'a ete trouvee pointant vers cette NVA. + RouteTable = Table de routage + RouteName = Nom de la route + AddressPrefix = Prefixe d'adresse + NextHopIpAddress = Adresse IP du prochain troncon + Tags = Balises + None = Aucun +'@ + } diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Diagram/Get-AbrDiagAzManagementGroup.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Diagram/Get-AbrDiagAzManagementGroup.ps1 new file mode 100644 index 0000000..028a1b0 --- /dev/null +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Diagram/Get-AbrDiagAzManagementGroup.ps1 @@ -0,0 +1,147 @@ +function Get-AbrDiagAzManagementGroup { + [CmdletBinding()] + param ( + [Parameter(Mandatory)] + [Object] $RootManagementGroup + ) + begin { + $LocalizedData = $reportTranslate.GetAbrAzManagementGroup + } + process { + try { + $DiagramTheme = if ($Options.DiagramTheme) { $Options.DiagramTheme } else { 'White' } + $DiagramDpi = if ($Options.DiagramDpi) { $Options.DiagramDpi } else { 96 } + # PScribo's Image -Percent scales off raw pixel count assuming a fixed 96 DPI baseline, + # so a higher render DPI must be offset by a proportionally lower Percent to keep the + # printed size on the page the same while still gaining pixel density. + $DiagramPercent = [Math]::Max(1, [Math]::Round(9600 / $DiagramDpi)) + $FontColor = if ($DiagramTheme -eq 'Black') { '#FFFFFF' } else { '#000000' } + $EdgeColor = if ($DiagramTheme -eq 'Black') { '#AAAAAA' } else { '#333333' } + $CellBgColor = if ($DiagramTheme -eq 'Black') { '#2D2D2D' } else { '#FFFFFF' } + $TableBorderColor = if ($DiagramTheme -eq 'Black') { '#AAAAAA' } else { '#333333' } + + $ModuleBase = (Get-Module -Name 'AsBuiltReport.Microsoft.Azure').ModuleBase + $IconPath = [System.IO.FileInfo](Join-Path $ModuleBase 'Icons') + $ImagesObj = @{ + 'MG' = 'management-groups.png' + 'Sub' = 'subscriptions.png' + 'Blank' = 'blank.png' + } + + # Pass 1: BFS to collect all MG info in root-to-leaf order + $MgList = [System.Collections.Generic.List[hashtable]]::new() + $MgQueue = [System.Collections.Queue]::new() + $MgQueue.Enqueue(@{ MG = $RootManagementGroup; ParentId = $null }) + while ($MgQueue.Count -gt 0) { + $Item = $MgQueue.Dequeue() + $CurrentMG = $Item.MG + $DirectSubs = @($CurrentMG.Children | + Where-Object { $_.Type -like '*subscriptions*' } | + Select-Object -ExpandProperty DisplayName) + $ChildMgIds = @($CurrentMG.Children | + Where-Object { $_.Type -like '*managementGroups*' } | + Select-Object -ExpandProperty Name) + $MgList.Add(@{ + Id = $CurrentMG.Name + DisplayName = $CurrentMG.DisplayName + ParentId = $Item.ParentId + Subscriptions = $DirectSubs + ChildMgIds = $ChildMgIds + }) + foreach ($MgChild in $CurrentMG.Children) { + if ($MgChild.Type -like '*managementGroups*') { + $MgQueue.Enqueue(@{ MG = $MgChild; ParentId = $CurrentMG.Name }) + } + } + } + + # Pass 2: propagate "has subscriptions in subtree" from leaves to root. + # Reverse BFS order guarantees children are processed before their parents. + $HasSubsInSubtree = [System.Collections.Generic.HashSet[string]]::new() + for ($i = $MgList.Count - 1; $i -ge 0; $i--) { + $MgInfo = $MgList[$i] + $ChildWithSubs = $MgInfo.ChildMgIds | Where-Object { $HasSubsInSubtree.Contains($_) } + if ($MgInfo.Subscriptions.Count -gt 0 -or $ChildWithSubs) { + $null = $HasSubsInSubtree.Add($MgInfo.Id) + } + } + + # Build PSGraph content — no outer graph{} wrapper. + # Each MG is a simple icon node. Subscriptions are SEPARATE collection nodes + # connected by edges so Graphviz places them at the same rank as sibling child MGs. + $DiagramGraph = & { + # MG nodes — all rendered as simple icon + name nodes + foreach ($MgInfo in $MgList) { + if (-not $HasSubsInSubtree.Contains($MgInfo.Id)) { continue } + $SafeId = 'MG_' + ($MgInfo.Id -replace '[^a-zA-Z0-9]', '_') + Add-HtmlNodeTable ` + -Name $SafeId ` + -ImagesObj $ImagesObj ` + -inputObject @($MgInfo.DisplayName) ` + -iconType 'MG' ` + -IconWidth 60 ` + -IconHeight 60 ` + -FontColor $FontColor ` + -CellBackgroundColor $CellBgColor ` + -NodeObject + } + + # Subscription collection nodes — one per MG that has direct subscriptions. + # Kept separate so Graphviz ranks them alongside sibling child MGs. + foreach ($MgInfo in $MgList) { + if (-not $HasSubsInSubtree.Contains($MgInfo.Id)) { continue } + if ($MgInfo.Subscriptions.Count -eq 0) { continue } + $SubNodeId = 'Sub_' + ($MgInfo.Id -replace '[^a-zA-Z0-9]', '_') + $SubLabel = "$($MgInfo.Subscriptions.Count) $($LocalizedData.SubscriptionCount)" + Add-HtmlNodeTable ` + -Name $SubNodeId ` + -ImagesObj $ImagesObj ` + -inputObject ([string[]]$MgInfo.Subscriptions) ` + -iconType 'Blank' ` + -Subgraph ` + -SubgraphLabel $SubLabel ` + -SubgraphIconType 'Sub' ` + -SubgraphIconWidth 60 ` + -SubgraphIconHeight 60 ` + -SubgraphLabelPos 'top' ` + -ColumnSize 1 ` + -TableBorderColor $TableBorderColor ` + -CellBackgroundColor $CellBgColor ` + -FontColor $FontColor ` + -NodeObject + } + + # Edges: MG → parent MG, and MG → its subscription collection node + foreach ($MgInfo in $MgList) { + if (-not $HasSubsInSubtree.Contains($MgInfo.Id)) { continue } + $SafeId = 'MG_' + ($MgInfo.Id -replace '[^a-zA-Z0-9]', '_') + if ($null -ne $MgInfo.ParentId -and $HasSubsInSubtree.Contains($MgInfo.ParentId)) { + $SafeParentId = 'MG_' + ($MgInfo.ParentId -replace '[^a-zA-Z0-9]', '_') + Edge $SafeParentId $SafeId @{ color = $EdgeColor; style = 'solid' } + } + if ($MgInfo.Subscriptions.Count -gt 0) { + $SubNodeId = 'Sub_' + ($MgInfo.Id -replace '[^a-zA-Z0-9]', '_') + Edge $SafeId $SubNodeId @{ color = $EdgeColor; style = 'solid' } + } + } + } + + $DiagramResult = New-AbrDiagram ` + -InputObject $DiagramGraph ` + -Format base64 ` + -MainDiagramLabel $LocalizedData.DiagramHeading ` + -IconPath $IconPath ` + -ImagesObj $ImagesObj ` + -MainGraphSize '6.5,9' ` + -Dpi $DiagramDpi ` + -DisableMainDiagramLogo + if ($DiagramResult) { + Image -Base64 $DiagramResult -Text $LocalizedData.DiagramAltText -Percent $DiagramPercent + BlankLine + } + } catch { + Write-PScriboMessage -IsWarning $_.Exception.Message + } + } + end {} +} diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAsrProtectedItems.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAsrProtectedItems.ps1 deleted file mode 100644 index 403102a..0000000 --- a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAsrProtectedItems.ps1 +++ /dev/null @@ -1,77 +0,0 @@ -function Get-AbrAsrProtectedItems { - <# - .SYNOPSIS - Used by As Built Report to retrieve Azure Site Recovery Protected Items information - .DESCRIPTION - - .NOTES - Version: 0.2.0 - Author: Tim Carman - Twitter: @tpcarman - Github: tpcarman - .EXAMPLE - - .LINK - - #> - [CmdletBinding()] - param ( - ) - - begin { - $LocalizedData = $reportTranslate.GetAbrAsrProtectedItems - Write-PScriboMessage ($LocalizedData.InfoLevel -f $InfoLevel.SiteRecovery) - } - - process { - Try { - if ($InfoLevel.SiteRecovery -gt 0) { - $AzRsvs = Get-AzRecoveryServicesVault | Sort-Object Name - if ($AzRsvs) { - foreach ($AzRsv in $AzRsvs) { - Write-PscriboMessage ($LocalizedData.Collecting -f $AzRsv.Name) - $AsrVaultContext = Set-AzRecoveryServicesAsrVaultContext -Vault $AzRsv -ErrorAction SilentlyContinue - $AsrPolicy = Get-AzRecoveryServicesAsrPolicy -ErrorAction SilentlyContinue | Where-Object {$_.ReplicationProvider -eq 'A2A'} - $AsrFabrics = Get-AzRecoveryServicesAsrFabric -ErrorAction SilentlyContinue - if ($AsrPolicy) { - Write-PscriboMessage $LocalizedData.CollectingItems - Section -Style Heading4 $LocalizedData.SubHeading { - foreach ($AsrFabric in $AsrFabrics) { - $AsrContainer = Get-AzRecoveryServicesAsrProtectionContainer -Fabric $AsrFabric -ErrorAction SilentlyContinue - $AsrReplicationProtectedItems = Get-AzRecoveryServicesAsrReplicationProtectedItem -ProtectionContainer $AsrContainer -ErrorAction SilentlyContinue | Sort-Object FriendlyName - if ($Healthcheck.SiteRecovery.ReplicationHealth) { - $AsrReplicationProtectedItems | Where-Object { $_.'replicationhealth' -eq 'Critical' } | Set-Style -Style Critical -Property 'replicationhealth' - } - if ($Healthcheck.SiteRecovery.FailoverHealth) { - $AsrReplicationProtectedItems | Where-Object { $_.'TestFailoverStateDescription' -ne 'None' } | Set-Style -Style Warning -Property 'TestFailoverStateDescription' - } - if ($AsrReplicationProtectedItems) { - Section -Style NOTOCHeading5 -ExcludeFromTOC $LocalizedData.Heading { - Paragraph ($LocalizedData.ParagraphSummary -f $AzSubscription.Name) - BlankLine - $TableParams = @{ - Name = "$($LocalizedData.TableHeading) - $($AzRsv.Name)" - List = $false - Headers = $LocalizedData.VirtualMachine, $LocalizedData.ReplicationHealth, $LocalizedData.State, $LocalizedData.ActiveLocation, $LocalizedData.TargetLocation, $LocalizedData.FailoverHealth - Columns = 'friendlyname', 'replicationhealth', 'protectionstatedescription', 'PrimaryFabricFriendlyName', 'RecoveryFabricFriendlyName', 'TestFailoverStateDescription' - ColumnWidths = 21, 15, 15, 17, 17, 15 - } - if ($Report.ShowTableCaptions) { - $TableParams['Caption'] = "- $($TableParams.Name)" - } - $AsrReplicationProtectedItems | Table @TableParams - } - } - } - } - } - } - } - } - } Catch { - Write-PScriboMessage -IsWarning $($_.Exception.Message) - } - } - - end {} -} \ No newline at end of file diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzRecoveryServicesVault.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzRecoveryServicesVault.ps1 deleted file mode 100644 index 5bd3ced..0000000 --- a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzRecoveryServicesVault.ps1 +++ /dev/null @@ -1,104 +0,0 @@ -function Get-AbrAzRecoveryServicesVault { - <# - .SYNOPSIS - Used by As Built Report to retrieve Azure Recovery Services Vault information - .DESCRIPTION - - .NOTES - Version: 0.2.0 - Author: Tim Carman - Twitter: @tpcarman - Github: tpcarman - .EXAMPLE - - .LINK - - #> - [CmdletBinding()] - param ( - ) - - begin { - $LocalizedData = $reportTranslate.GetAbrAzRecoveryServicesVault - Write-PScriboMessage ($LocalizedData.InfoLevel -f $InfoLevel.RecoveryServicesVault) - } - - process { - Try { - if ($InfoLevel.RecoveryServicesVault -gt 0) { - $AzRsvs = Get-AzRecoveryServicesVault | Sort-Object Name - if ($AzRsvs) { - Write-PscriboMessage $LocalizedData.Collecting - Section -Style Heading4 $LocalizedData.Heading { - if ($Options.ShowSectionInfo) { - Paragraph $LocalizedData.SectionInfo - BlankLine - } - $AzRsvInfo = @() - foreach ($AzRsv in $AzRsvs) { - $InObj = [Ordered]@{ - $LocalizedData.Name = $AzRsv.Name - $LocalizedData.ResourceGroup = $AzRsv.ResourceGroupName - $LocalizedData.Location = $AzLocationLookup."$($AzRsv.Location)" - $LocalizedData.Subscription = "$($AzSubscriptionLookup.(($AzRsv.Id).split('/')[2]))" - $LocalizedData.SubscriptionID = ($AzRsv.Id).split('/')[2] - $LocalizedData.ProvisioningState = $AzRsv.Properties.ProvisioningState - $LocalizedData.PrivateEndpointStateForBackup = Switch ($AzRsv.Properties.PrivateEndpointStateForBackup) { - $null { $LocalizedData.None } - default { $AzRsv.Properties.PrivateEndpointStateForBackup } - } - $LocalizedData.PrivateEndpointStateForSiteRecovery = Switch ($AzRsv.Properties.PrivateEndpointStateForSiteRecovery) { - $null { $LocalizedData.None } - default { $AzRsv.Properties.PrivateEndpointStateForSiteRecovery } - } - } - $AzRsvInfo += [PSCustomObject]$InObj - } - - # Apply health check highlighting - if ($Healthcheck.RecoveryServicesVault.ProvisioningState) { - $AzRsvInfo | Where-Object { $_.$($LocalizedData.ProvisioningState) -ne 'Succeeded' } | Set-Style -Style Critical -Property $LocalizedData.ProvisioningState - } - if ($Healthcheck.RecoveryServicesVault.PrivateEndpointStateForBackup) { - $AzRsvInfo | Where-Object { $_.$($LocalizedData.PrivateEndpointStateForBackup) -eq $LocalizedData.None } | Set-Style -Style Warning -Property $LocalizedData.PrivateEndpointStateForBackup - } - - if ($InfoLevel.RecoveryServicesVault -ge 2) { - Paragraph ($LocalizedData.ParagraphDetail -f $AzSubscription.Name) - foreach ($AzRsv in $AzRsvInfo) { - Section -Style NOTOCHeading5 -ExcludeFromTOC "$($AzRsv.($LocalizedData.Name))" { - $TableParams = @{ - Name = "$($LocalizedData.Heading) - $($AzRsv.($LocalizedData.Name))" - List = $true - ColumnWidths = 40, 60 - } - if ($Report.ShowTableCaptions) { - $TableParams['Caption'] = "- $($TableParams.Name)" - } - $AzRsv | Table @TableParams - } - } - } else { - Paragraph ($LocalizedData.ParagraphSummary -f $AzSubscription.Name) - BlankLine - $TableParams = @{ - Name = "$($LocalizedData.TableHeadings) - $($AzSubscription.Name)" - List = $false - Columns = $LocalizedData.Name, $LocalizedData.ResourceGroup, $LocalizedData.Location - ColumnWidths = 33, 34, 33 - } - if ($Report.ShowTableCaptions) { - $TableParams['Caption'] = "- $($TableParams.Name)" - } - $AzRsvinfo | Table @TableParams - } - } - } - } - } Catch { - Write-PScriboMessage -IsWarning $($_.Exception.Message) - } - } - - end {} -} \ No newline at end of file diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Convert-DataSize.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Convert-DataSize.ps1 similarity index 100% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Convert-DataSize.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Convert-DataSize.ps1 diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAsrProtectedItems.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAsrProtectedItems.ps1 new file mode 100644 index 0000000..55a6fa9 --- /dev/null +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAsrProtectedItems.ps1 @@ -0,0 +1,130 @@ +function Get-AbrAsrProtectedItems { + <# + .SYNOPSIS + Used by As Built Report to retrieve Azure Site Recovery Protected Items information + .DESCRIPTION + + .NOTES + Version: 0.2.0 + Author: Tim Carman + Twitter: @tpcarman + Github: tpcarman + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param ( + ) + + begin { + $LocalizedData = $reportTranslate.GetAbrAsrProtectedItems + Write-PScriboMessage ($LocalizedData.InfoLevel -f $InfoLevel.SiteRecovery) + } + + process { + Try { + if ($InfoLevel.SiteRecovery -gt 0) { + $AzRsvs = Get-AzRecoveryServicesVault | Sort-Object Name + if ($AzRsvs) { + foreach ($AzRsv in $AzRsvs) { + Write-PscriboMessage ($LocalizedData.Collecting -f $AzRsv.Name) + $null = Set-AzRecoveryServicesAsrVaultContext -Vault $AzRsv -ErrorAction SilentlyContinue + $AsrPolicy = Get-AzRecoveryServicesAsrPolicy -ErrorAction SilentlyContinue + $AsrFabrics = Get-AzRecoveryServicesAsrFabric -ErrorAction SilentlyContinue + if ($AsrPolicy) { + Write-PscriboMessage $LocalizedData.CollectingItems + $AllFabricItems = [Ordered]@{} + foreach ($AsrFabric in $AsrFabrics) { + $AsrContainer = Get-AzRecoveryServicesAsrProtectionContainer -Fabric $AsrFabric -ErrorAction SilentlyContinue + $AsrReplicationProtectedItems = Get-AzRecoveryServicesAsrReplicationProtectedItem -ProtectionContainer $AsrContainer -ErrorAction SilentlyContinue | Sort-Object FriendlyName + if ($Healthcheck.SiteRecovery.ReplicationHealth) { + $AsrReplicationProtectedItems | Where-Object { $_.'replicationhealth' -eq 'Critical' } | Set-Style -Style Critical -Property 'replicationhealth' + } + if ($Healthcheck.SiteRecovery.FailoverHealth) { + $AsrReplicationProtectedItems | Where-Object { $_.'TestFailoverStateDescription' -eq 'Failed' } | Set-Style -Style Critical -Property 'TestFailoverStateDescription' + } + if ($Healthcheck.SiteRecovery.NoTestFailover) { + $AsrReplicationProtectedItems | Where-Object { $_.'TestFailoverStateDescription' -eq 'None' } | Set-Style -Style Warning -Property 'TestFailoverStateDescription' + } + $AllFabricItems[$AsrFabric.Name] = $AsrReplicationProtectedItems + } + Section -Style Heading4 $LocalizedData.SubHeading { + if ($InfoLevel.SiteRecovery -ge 2) { + Paragraph ($LocalizedData.ParagraphDetail -f $AzSubscription.Name) + } + foreach ($AsrFabric in $AsrFabrics) { + $AsrReplicationProtectedItems = $AllFabricItems[$AsrFabric.Name] + if ($AsrReplicationProtectedItems) { + if ($InfoLevel.SiteRecovery -ge 2) { + foreach ($Item in $AsrReplicationProtectedItems) { + Section -Style NOTOCHeading5 -ExcludeFromTOC $Item.FriendlyName { + $InObj = [Ordered]@{ + $LocalizedData.VirtualMachine = $Item.FriendlyName + $LocalizedData.ReplicationProvider = $Item.ReplicationProvider + $LocalizedData.ReplicationHealth = $Item.ReplicationHealth + $LocalizedData.State = $Item.ProtectionStateDescription + $LocalizedData.ActiveLocation = $Item.PrimaryFabricFriendlyName + $LocalizedData.TargetLocation = $Item.RecoveryFabricFriendlyName + $LocalizedData.FailoverHealth = $Item.TestFailoverStateDescription + } + if ($Item.ReplicationProvider -eq 'A2A' -and $Item.ProviderSpecificDetails) { + $InObj[$LocalizedData.Rpo] = $( + if ($null -ne $Item.ProviderSpecificDetails.RpoInSeconds) { + [math]::Round($Item.ProviderSpecificDetails.RpoInSeconds / 60, 1) + } else { + $LocalizedData.NotAvailable + } + ) + $InObj[$LocalizedData.LastRpoCalculated] = $Item.ProviderSpecificDetails.LastRpoCalculatedTime + $InObj[$LocalizedData.LastHeartbeat] = $Item.ProviderSpecificDetails.LastHeartbeat + $InObj[$LocalizedData.RecoveryVmSize] = $Item.ProviderSpecificDetails.RecoveryAzureVMSize + $InObj[$LocalizedData.RecoveryAvailabilityZone] = Switch ($Item.ProviderSpecificDetails.RecoveryAvailabilityZone) { + $null { $LocalizedData.None } + default { $Item.ProviderSpecificDetails.RecoveryAvailabilityZone } + } + } + $DetailObj = [PSCustomObject]$InObj + $TableParams = @{ + Name = "$($LocalizedData.TableHeading) - $($Item.FriendlyName)" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $DetailObj | Table @TableParams + } + } + } else { + Section -Style NOTOCHeading5 -ExcludeFromTOC $LocalizedData.Heading { + Paragraph ($LocalizedData.ParagraphSummary -f $AzSubscription.Name) + BlankLine + $TableParams = @{ + Name = "$($LocalizedData.TableHeading) - $($AzRsv.Name)" + List = $false + Headers = $LocalizedData.VirtualMachine, $LocalizedData.ReplicationHealth, $LocalizedData.State, $LocalizedData.ActiveLocation, $LocalizedData.TargetLocation, $LocalizedData.FailoverHealth + Columns = 'friendlyname', 'replicationhealth', 'protectionstatedescription', 'PrimaryFabricFriendlyName', 'RecoveryFabricFriendlyName', 'TestFailoverStateDescription' + ColumnWidths = 21, 15, 15, 17, 17, 15 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AsrReplicationProtectedItems | Table @TableParams + } + } + } + } + } + } + } + } + } + } Catch { + Write-PScriboMessage -IsWarning $($_.Exception.Message) + } + } + + end {} +} diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzApplicationGateway.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzApplicationGateway.ps1 new file mode 100644 index 0000000..6f8c285 --- /dev/null +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzApplicationGateway.ps1 @@ -0,0 +1,248 @@ +function Get-AbrAzApplicationGateway { + <# + .SYNOPSIS + Used by As Built Report to retrieve Azure Application Gateway information + .DESCRIPTION + Documents the configuration of Azure Application Gateways including SKU, WAF settings, + HTTP listeners, backend address pools, and request routing rules. + .NOTES + Version: 0.1.0 + Author: Tim Carman + Twitter: @tpcarman + Github: tpcarman + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param () + + begin { + $LocalizedData = $reportTranslate.GetAbrAzApplicationGateway + Write-PScriboMessage ($LocalizedData.InfoLevel -f $InfoLevel.ApplicationGateway) + } + + process { + try { + if ($InfoLevel.ApplicationGateway -ge 1) { + $AzAppGateways = Get-AzApplicationGateway -ErrorAction SilentlyContinue | Sort-Object Name + if ($AzAppGateways) { + Write-PScriboMessage $LocalizedData.Collecting + Section -Style Heading4 $LocalizedData.Heading { + if ($Options.ShowSectionInfo) { + Paragraph $LocalizedData.SectionInfo + BlankLine + } + + $AzAppGatewayInfo = @() + foreach ($AzAppGw in $AzAppGateways) { + $SubnetId = if ($AzAppGw.GatewayIPConfigurations -and $AzAppGw.GatewayIPConfigurations[0].Subnet.Id) { + $AzAppGw.GatewayIPConfigurations[0].Subnet.Id + } else { $null } + $VirtualNetwork = if ($SubnetId) { $SubnetId.split('/')[8] } else { $LocalizedData.None } + $Subnet = if ($SubnetId) { $SubnetId.split('/')[-1] } else { $LocalizedData.None } + + $Capacity = if ($AzAppGw.AutoscaleConfiguration) { + $MaxCap = if ($null -ne $AzAppGw.AutoscaleConfiguration.MaxCapacity) { + $AzAppGw.AutoscaleConfiguration.MaxCapacity + } else { + $LocalizedData.Unlimited + } + "$($AzAppGw.AutoscaleConfiguration.MinCapacity) - $MaxCap" + } else { + [string]$AzAppGw.Sku.Capacity + } + + $WafEnabled = $AzAppGw.FirewallPolicy -or ( + $AzAppGw.WebApplicationFirewallConfiguration -and $AzAppGw.WebApplicationFirewallConfiguration.Enabled + ) + $WafMode = if ($AzAppGw.WebApplicationFirewallConfiguration) { + $AzAppGw.WebApplicationFirewallConfiguration.FirewallMode + } elseif ($AzAppGw.FirewallPolicy) { + 'Policy' + } else { + $LocalizedData.NotApplicable + } + + $FrontendIPs = ($AzAppGw.FrontendIPConfigurations | ForEach-Object { + if ($_.PublicIPAddress) { + "Public: $(($_.PublicIPAddress.Id).split('/')[-1])" + } elseif ($_.PrivateIPAddress) { + "Private: $($_.PrivateIPAddress)" + } + }) -join [Environment]::NewLine + + $InObj = [Ordered]@{ + $LocalizedData.Name = $AzAppGw.Name + $LocalizedData.ResourceGroup = $AzAppGw.ResourceGroupName + $LocalizedData.Location = $AzLocationLookup."$($AzAppGw.Location)" + $LocalizedData.Subscription = "$($AzSubscriptionLookup.(($AzAppGw.Id).split('/')[2]))" + $LocalizedData.SubscriptionID = ($AzAppGw.Id).split('/')[2] + $LocalizedData.VirtualNetwork = $VirtualNetwork + $LocalizedData.Subnet = $Subnet + $LocalizedData.SKU = $AzAppGw.Sku.Name + $LocalizedData.Tier = $AzAppGw.Sku.Tier + $LocalizedData.Capacity = $Capacity + $LocalizedData.WafEnabled = $WafEnabled + $LocalizedData.WafMode = $WafMode + $LocalizedData.Http2Enabled = $AzAppGw.EnableHttp2 + $LocalizedData.FrontendIPs = if ($FrontendIPs) { $FrontendIPs } else { $LocalizedData.None } + $LocalizedData.OperationalState = $AzAppGw.OperationalState + $LocalizedData.ProvisioningState = $AzAppGw.ProvisioningState + } + + if ($Options.ShowTags) { + $InObj[$LocalizedData.Tags] = if ($null -eq $AzAppGw.Tags -or $AzAppGw.Tags.Count -eq 0) { + $LocalizedData.None + } else { + ($AzAppGw.Tags.Keys | ForEach-Object { "$_`:`t$($AzAppGw.Tags[$_])" }) -join [Environment]::NewLine + } + } + + $AzAppGatewayInfo += [PSCustomObject]$InObj + } + + if ($Healthcheck.ApplicationGateway.ProvisioningState) { + $AzAppGatewayInfo | Where-Object { $_.$($LocalizedData.ProvisioningState) -ne 'Succeeded' } | Set-Style -Style Critical -Property $LocalizedData.ProvisioningState + } + if ($Healthcheck.ApplicationGateway.OperationalState) { + $AzAppGatewayInfo | Where-Object { $_.$($LocalizedData.OperationalState) -ne 'Running' } | Set-Style -Style Warning -Property $LocalizedData.OperationalState + } + + if ($InfoLevel.ApplicationGateway -ge 2) { + Paragraph ($LocalizedData.ParagraphDetail -f $AzSubscription.Name) + foreach ($AzAppGwItem in $AzAppGatewayInfo) { + $GwName = $AzAppGwItem.($LocalizedData.Name) + $GwRg = $AzAppGwItem.($LocalizedData.ResourceGroup) + $FullGw = $AzAppGateways | Where-Object { $_.Name -eq $GwName -and $_.ResourceGroupName -eq $GwRg } + Section -Style NOTOCHeading5 -ExcludeFromTOC $GwName { + $TableParams = @{ + Name = "$($LocalizedData.TableHeading) - $GwName" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AzAppGwItem | Table @TableParams + + if ($FullGw.HttpListeners) { + Section -Style NOTOCHeading6 -ExcludeFromTOC $LocalizedData.Listeners { + $PortLookup = @{} + foreach ($FrontendPort in $FullGw.FrontendPorts) { + $PortLookup[$FrontendPort.Id] = $FrontendPort.Port + } + $ListenerInfo = @() + foreach ($Listener in $FullGw.HttpListeners) { + $Port = if ($Listener.FrontendPort.Id -and $PortLookup.ContainsKey($Listener.FrontendPort.Id)) { + $PortLookup[$Listener.FrontendPort.Id] + } else { + $LocalizedData.NotApplicable + } + $HostNames = if ($Listener.HostNames -and $Listener.HostNames.Count -gt 0) { + $Listener.HostNames -join ', ' + } elseif ($Listener.HostName) { + $Listener.HostName + } else { + $LocalizedData.None + } + $InObj = [Ordered]@{ + $LocalizedData.ListenerName = $Listener.Name + $LocalizedData.Protocol = $Listener.Protocol + $LocalizedData.Port = $Port + $LocalizedData.HostName = $HostNames + } + $ListenerInfo += [PSCustomObject]$InObj + } + $TableParams = @{ + Name = "$($LocalizedData.Listeners) - $GwName" + List = $false + ColumnWidths = 30, 15, 10, 45 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $ListenerInfo | Table @TableParams + } + } + + if ($FullGw.BackendAddressPools) { + Section -Style NOTOCHeading6 -ExcludeFromTOC $LocalizedData.BackendPools { + $PoolInfo = @() + foreach ($Pool in $FullGw.BackendAddressPools) { + $Targets = if ($Pool.BackendAddresses -and $Pool.BackendAddresses.Count -gt 0) { + ($Pool.BackendAddresses | ForEach-Object { + if ($_.Fqdn) { $_.Fqdn } elseif ($_.IpAddress) { $_.IpAddress } + }) -join [Environment]::NewLine + } else { + $LocalizedData.None + } + $InObj = [Ordered]@{ + $LocalizedData.PoolName = $Pool.Name + $LocalizedData.BackendTargets = $Targets + } + $PoolInfo += [PSCustomObject]$InObj + } + $TableParams = @{ + Name = "$($LocalizedData.BackendPools) - $GwName" + List = $false + ColumnWidths = 30, 70 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $PoolInfo | Table @TableParams + } + } + + if ($FullGw.RequestRoutingRules) { + Section -Style NOTOCHeading6 -ExcludeFromTOC $LocalizedData.RoutingRules { + $RuleInfo = @() + foreach ($Rule in $FullGw.RequestRoutingRules) { + $InObj = [Ordered]@{ + $LocalizedData.RuleName = $Rule.Name + $LocalizedData.RuleType = $Rule.RuleType + $LocalizedData.ListenerName = if ($Rule.HttpListener.Id) { ($Rule.HttpListener.Id).split('/')[-1] } else { $LocalizedData.None } + $LocalizedData.BackendPool = if ($Rule.BackendAddressPool.Id) { ($Rule.BackendAddressPool.Id).split('/')[-1] } else { $LocalizedData.None } + $LocalizedData.BackendHttpSettings = if ($Rule.BackendHttpSettings.Id) { ($Rule.BackendHttpSettings.Id).split('/')[-1] } else { $LocalizedData.None } + } + $RuleInfo += [PSCustomObject]$InObj + } + $TableParams = @{ + Name = "$($LocalizedData.RoutingRules) - $GwName" + List = $false + ColumnWidths = 20, 15, 25, 20, 20 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $RuleInfo | Table @TableParams + } + } + } + } + } else { + Paragraph ($LocalizedData.ParagraphSummary -f $AzSubscription.Name) + BlankLine + $TableParams = @{ + Name = "$($LocalizedData.TableHeading) - $($AzSubscription.Name)" + List = $false + Columns = $LocalizedData.Name, $LocalizedData.ResourceGroup, $LocalizedData.Location, $LocalizedData.SKU, $LocalizedData.OperationalState, $LocalizedData.ProvisioningState + ColumnWidths = 20, 20, 15, 20, 10, 15 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AzAppGatewayInfo | Table @TableParams + } + } + } + } + } catch { + Write-PScriboMessage -IsWarning "$($LocalizedData.ErrorMessage) $($_.Exception.Message)" + } + } + + end {} +} diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzAsrNetworkMapping.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzAsrNetworkMapping.ps1 new file mode 100644 index 0000000..0d87f84 --- /dev/null +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzAsrNetworkMapping.ps1 @@ -0,0 +1,114 @@ +function Get-AbrAzAsrNetworkMapping { + <# + .SYNOPSIS + Used by As Built Report to retrieve Azure Site Recovery Network Mapping information + .DESCRIPTION + + .NOTES + Version: 0.1.0 + Author: Tim Carman + Twitter: @tpcarman + Github: tpcarman + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param ( + ) + + begin { + $LocalizedData = $reportTranslate.GetAbrAzAsrNetworkMapping + Write-PScriboMessage ($LocalizedData.InfoLevel -f $InfoLevel.AsrNetworkMapping) + } + + process { + Try { + if ($InfoLevel.AsrNetworkMapping -gt 0) { + $AzRsvs = Get-AzRecoveryServicesVault | Sort-Object Name + if ($AzRsvs) { + foreach ($AzRsv in $AzRsvs) { + $null = Set-AzRecoveryServicesAsrVaultContext -Vault $AzRsv -ErrorAction SilentlyContinue + $AsrFabrics = Get-AzRecoveryServicesAsrFabric -ErrorAction SilentlyContinue + $AllNetworkMappings = @() + foreach ($Fabric in $AsrFabrics) { + $AsrNetworks = Get-AzRecoveryServicesAsrNetwork -Fabric $Fabric -ErrorAction SilentlyContinue + foreach ($AsrNetwork in $AsrNetworks) { + $Mappings = Get-AzRecoveryServicesAsrNetworkMapping -Fabric $Fabric -Network $AsrNetwork -ErrorAction SilentlyContinue + if ($Mappings) { $AllNetworkMappings += $Mappings } + } + } + $AllNetworkMappings = $AllNetworkMappings | Sort-Object Name + if ($AllNetworkMappings) { + Write-PScriboMessage ($LocalizedData.Collecting -f $AzRsv.Name) + Section -Style Heading4 "$($LocalizedData.Heading) - $($AzRsv.Name)" { + if ($Options.ShowSectionInfo) { + Paragraph $LocalizedData.SectionInfo + BlankLine + } + $MappingInfo = @() + foreach ($Mapping in $AllNetworkMappings) { + $InObj = [Ordered]@{ + $LocalizedData.Name = $Mapping.Name + $LocalizedData.PrimaryNetwork = Switch ($Mapping.PrimaryNetworkFriendlyName) { + $null { $LocalizedData.None } + default { $Mapping.PrimaryNetworkFriendlyName } + } + $LocalizedData.RecoveryNetwork = Switch ($Mapping.RecoveryNetworkFriendlyName) { + $null { $LocalizedData.None } + default { $Mapping.RecoveryNetworkFriendlyName } + } + $LocalizedData.MappingState = Switch ($Mapping.PairingStatus) { + $null { $LocalizedData.None } + default { $Mapping.PairingStatus } + } + } + $MappingInfo += [PSCustomObject]$InObj + } + + if ($Healthcheck.AsrNetworkMapping.MappingState) { + $MappingInfo | Where-Object { $_.$($LocalizedData.MappingState) -notin @('Paired', $LocalizedData.None) } | Set-Style -Style Warning -Property $LocalizedData.MappingState + } + + if ($InfoLevel.AsrNetworkMapping -ge 2) { + Paragraph ($LocalizedData.ParagraphDetail -f $AzRsv.Name) + foreach ($Mapping in $MappingInfo) { + Section -Style NOTOCHeading5 -ExcludeFromTOC "$($Mapping.($LocalizedData.Name))" { + $TableParams = @{ + Name = "$($LocalizedData.Heading) - $($Mapping.($LocalizedData.Name))" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $Mapping | Table @TableParams + } + } + } else { + Paragraph ($LocalizedData.ParagraphSummary -f $AzRsv.Name) + BlankLine + $TableParams = @{ + Name = "$($LocalizedData.TableHeadings) - $($AzRsv.Name)" + List = $false + Columns = $LocalizedData.Name, $LocalizedData.PrimaryNetwork, $LocalizedData.RecoveryNetwork, $LocalizedData.MappingState + ColumnWidths = 25, 30, 30, 15 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $MappingInfo | Table @TableParams + } + } + } + } + } + } + } Catch { + Write-PScriboMessage -IsWarning $($_.Exception.Message) + } + } + + end {} +} diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzAsrPolicy.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzAsrPolicy.ps1 new file mode 100644 index 0000000..fb30e0b --- /dev/null +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzAsrPolicy.ps1 @@ -0,0 +1,120 @@ +function Get-AbrAzAsrPolicy { + <# + .SYNOPSIS + Used by As Built Report to retrieve Azure Site Recovery Replication Policy information + .DESCRIPTION + + .NOTES + Version: 0.1.0 + Author: Tim Carman + Twitter: @tpcarman + Github: tpcarman + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param ( + ) + + begin { + $LocalizedData = $reportTranslate.GetAbrAzAsrPolicy + Write-PScriboMessage ($LocalizedData.InfoLevel -f $InfoLevel.AsrPolicy) + } + + process { + Try { + if ($InfoLevel.AsrPolicy -gt 0) { + $AzRsvs = Get-AzRecoveryServicesVault | Sort-Object Name + if ($AzRsvs) { + foreach ($AzRsv in $AzRsvs) { + $null = Set-AzRecoveryServicesAsrVaultContext -Vault $AzRsv -ErrorAction SilentlyContinue + $AsrPolicies = Get-AzRecoveryServicesAsrPolicy -ErrorAction SilentlyContinue | Sort-Object Name + if ($AsrPolicies) { + Write-PScriboMessage ($LocalizedData.Collecting -f $AzRsv.Name) + Section -Style Heading4 "$($LocalizedData.Heading) - $($AzRsv.Name)" { + if ($Options.ShowSectionInfo) { + Paragraph $LocalizedData.SectionInfo + BlankLine + } + $PolicyInfo = @() + foreach ($Policy in $AsrPolicies) { + $ProvSettings = $Policy.ReplicationProviderSettings + $InObj = [Ordered]@{ + $LocalizedData.Name = $Policy.Name + $LocalizedData.Provider = $Policy.ReplicationProvider + $LocalizedData.RpoThreshold = $( + if ($null -ne $ProvSettings.RecoveryPointThresholdInMinutes) { $ProvSettings.RecoveryPointThresholdInMinutes } + else { $LocalizedData.NotApplicable } + ) + $LocalizedData.RecoveryPointHistory = $( + if ($null -ne $ProvSettings.RecoveryPointHistory) { $ProvSettings.RecoveryPointHistory } + elseif ($null -ne $ProvSettings.RecoveryPointHistoryDurationInHours) { $ProvSettings.RecoveryPointHistoryDurationInHours } + else { $LocalizedData.NotApplicable } + ) + $LocalizedData.AppConsistentFrequency = $( + if ($null -ne $ProvSettings.AppConsistentFrequencyInMinutes) { $ProvSettings.AppConsistentFrequencyInMinutes } + elseif ($null -ne $ProvSettings.ApplicationConsistentSnapshotFrequencyInHours) { $ProvSettings.ApplicationConsistentSnapshotFrequencyInHours * 60 } + else { $LocalizedData.NotApplicable } + ) + $LocalizedData.CrashConsistentFrequency = $( + if ($null -ne $ProvSettings.CrashConsistentFrequencyInMinutes) { $ProvSettings.CrashConsistentFrequencyInMinutes } + else { $LocalizedData.NotApplicable } + ) + $LocalizedData.MultiVmSync = Switch ($ProvSettings.MultiVmSyncStatus) { + $null { $LocalizedData.NotApplicable } + default { $ProvSettings.MultiVmSyncStatus } + } + } + $PolicyInfo += [PSCustomObject]$InObj + } + + if ($Healthcheck.AsrPolicy.AppConsistentSnapshot) { + $PolicyInfo | Where-Object { + $_.$($LocalizedData.AppConsistentFrequency) -eq 0 -or + $_.$($LocalizedData.AppConsistentFrequency) -eq $LocalizedData.NotApplicable + } | Set-Style -Style Warning -Property $LocalizedData.AppConsistentFrequency + } + + if ($InfoLevel.AsrPolicy -ge 2) { + Paragraph ($LocalizedData.ParagraphDetail -f $AzRsv.Name) + foreach ($Policy in $PolicyInfo) { + Section -Style NOTOCHeading5 -ExcludeFromTOC "$($Policy.($LocalizedData.Name))" { + $TableParams = @{ + Name = "$($LocalizedData.Heading) - $($Policy.($LocalizedData.Name))" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $Policy | Table @TableParams + } + } + } else { + Paragraph ($LocalizedData.ParagraphSummary -f $AzRsv.Name) + BlankLine + $TableParams = @{ + Name = "$($LocalizedData.TableHeadings) - $($AzRsv.Name)" + List = $false + Columns = $LocalizedData.Name, $LocalizedData.Provider, $LocalizedData.RpoThreshold, $LocalizedData.RecoveryPointHistory, $LocalizedData.AppConsistentFrequency + ColumnWidths = 26, 20, 18, 18, 18 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $PolicyInfo | Table @TableParams + } + } + } + } + } + } + } Catch { + Write-PScriboMessage -IsWarning $($_.Exception.Message) + } + } + + end {} +} diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzAsrRecoveryPlan.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzAsrRecoveryPlan.ps1 new file mode 100644 index 0000000..bc8f13e --- /dev/null +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzAsrRecoveryPlan.ps1 @@ -0,0 +1,98 @@ +function Get-AbrAzAsrRecoveryPlan { + <# + .SYNOPSIS + Used by As Built Report to retrieve Azure Site Recovery Recovery Plan information + .DESCRIPTION + + .NOTES + Version: 0.1.0 + Author: Tim Carman + Twitter: @tpcarman + Github: tpcarman + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param ( + ) + + begin { + $LocalizedData = $reportTranslate.GetAbrAzAsrRecoveryPlan + Write-PScriboMessage ($LocalizedData.InfoLevel -f $InfoLevel.AsrRecoveryPlan) + } + + process { + Try { + if ($InfoLevel.AsrRecoveryPlan -gt 0) { + $AzRsvs = Get-AzRecoveryServicesVault | Sort-Object Name + if ($AzRsvs) { + foreach ($AzRsv in $AzRsvs) { + $null = Set-AzRecoveryServicesAsrVaultContext -Vault $AzRsv -ErrorAction SilentlyContinue + $AsrRecoveryPlans = Get-AzRecoveryServicesAsrRecoveryPlan -ErrorAction SilentlyContinue | Sort-Object Name + if ($AsrRecoveryPlans) { + Write-PScriboMessage ($LocalizedData.Collecting -f $AzRsv.Name) + Section -Style Heading4 "$($LocalizedData.Heading) - $($AzRsv.Name)" { + if ($Options.ShowSectionInfo) { + Paragraph $LocalizedData.SectionInfo + BlankLine + } + $PlanInfo = @() + foreach ($Plan in $AsrRecoveryPlans) { + $ProtectedItemCount = ($Plan.Groups | ForEach-Object { $_.ReplicationProtectedItems } | Measure-Object).Count + $InObj = [Ordered]@{ + $LocalizedData.Name = $Plan.Name + $LocalizedData.PrimaryFabric = $Plan.PrimaryFabricFriendlyName + $LocalizedData.RecoveryFabric = $Plan.RecoveryFabricFriendlyName + $LocalizedData.GroupCount = ($Plan.Groups | Measure-Object).Count + $LocalizedData.ProtectedItemCount = $ProtectedItemCount + $LocalizedData.FailoverDeploymentModel = Switch ($Plan.FailoverDeploymentModel) { + $null { $LocalizedData.None } + default { $Plan.FailoverDeploymentModel } + } + } + $PlanInfo += [PSCustomObject]$InObj + } + + if ($InfoLevel.AsrRecoveryPlan -ge 2) { + Paragraph ($LocalizedData.ParagraphDetail -f $AzRsv.Name) + foreach ($Plan in $PlanInfo) { + Section -Style NOTOCHeading5 -ExcludeFromTOC "$($Plan.($LocalizedData.Name))" { + $TableParams = @{ + Name = "$($LocalizedData.Heading) - $($Plan.($LocalizedData.Name))" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $Plan | Table @TableParams + } + } + } else { + Paragraph ($LocalizedData.ParagraphSummary -f $AzRsv.Name) + BlankLine + $TableParams = @{ + Name = "$($LocalizedData.TableHeadings) - $($AzRsv.Name)" + List = $false + Columns = $LocalizedData.Name, $LocalizedData.PrimaryFabric, $LocalizedData.RecoveryFabric, $LocalizedData.GroupCount, $LocalizedData.ProtectedItemCount + ColumnWidths = 30, 20, 20, 15, 15 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $PlanInfo | Table @TableParams + } + } + } + } + } + } + } Catch { + Write-PScriboMessage -IsWarning $($_.Exception.Message) + } + } + + end {} +} diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzAutomationAccount.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzAutomationAccount.ps1 new file mode 100644 index 0000000..67e4285 --- /dev/null +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzAutomationAccount.ps1 @@ -0,0 +1,209 @@ +function Get-AbrAzAutomationAccount { + <# + .SYNOPSIS + Used by As Built Report to retrieve Azure Automation Account information + .DESCRIPTION + Documents the configuration of Azure Automation Accounts including runbooks, + variables, schedules, and credentials. + .NOTES + Version: 0.1.0 + Author: Tim Carman + Twitter: @tpcarman + Github: tpcarman + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param () + + begin { + $LocalizedData = $reportTranslate.GetAbrAzAutomationAccount + Write-PScriboMessage ($LocalizedData.InfoLevel -f $InfoLevel.AutomationAccount) + } + + process { + try { + if ($InfoLevel.AutomationAccount -ge 1) { + $AzAutomationAccounts = Get-AzAutomationAccount -ErrorAction SilentlyContinue | Sort-Object AutomationAccountName + if ($AzAutomationAccounts) { + # The list API does not populate State; build a lookup from ARM resource properties instead + $AzAutoStateMap = @{} + $AzAutoResources = Get-AzResource -ResourceType 'Microsoft.Automation/automationAccounts' -ExpandProperties -ErrorAction SilentlyContinue + foreach ($AzAutoResource in $AzAutoResources) { + $AzAutoStateMap["$($AzAutoResource.ResourceGroupName)|$($AzAutoResource.Name)"] = $AzAutoResource.Properties.state + } + + Write-PScriboMessage $LocalizedData.Collecting + Section -Style Heading4 $LocalizedData.Heading { + if ($Options.ShowSectionInfo) { + Paragraph $LocalizedData.SectionInfo + BlankLine + } + + $AzAutomationAccountInfo = @() + foreach ($AzAutomationAccount in $AzAutomationAccounts) { + $InObj = [Ordered]@{ + $LocalizedData.Name = $AzAutomationAccount.AutomationAccountName + $LocalizedData.ResourceGroup = $AzAutomationAccount.ResourceGroupName + $LocalizedData.Location = $AzLocationLookup."$($AzAutomationAccount.Location)" + $LocalizedData.Subscription = "$($AzSubscriptionLookup.($AzAutomationAccount.SubscriptionId))" + $LocalizedData.SubscriptionID = $AzAutomationAccount.SubscriptionId + $LocalizedData.State = $AzAutoStateMap["$($AzAutomationAccount.ResourceGroupName)|$($AzAutomationAccount.AutomationAccountName)"] + } + + if ($Options.ShowTags) { + $InObj[$LocalizedData.Tags] = if ($null -eq $AzAutomationAccount.Tags -or $AzAutomationAccount.Tags.Count -eq 0) { + $LocalizedData.None + } else { + ($AzAutomationAccount.Tags.GetEnumerator() | ForEach-Object { "$($_.Key):`t$($_.Value)" }) -join [Environment]::NewLine + } + } + + $AzAutomationAccountInfo += [PSCustomObject]$InObj + } + + if ($Healthcheck.AutomationAccount.State) { + $AzAutomationAccountInfo | Where-Object { $_.$($LocalizedData.State) -ne 'Ok' } | Set-Style -Style Critical -Property $LocalizedData.State + } + + if ($InfoLevel.AutomationAccount -ge 2) { + Paragraph ($LocalizedData.ParagraphDetail -f $AzSubscription.Name) + BlankLine + foreach ($AzAutoAcctItem in $AzAutomationAccountInfo) { + $AcctName = $AzAutoAcctItem.($LocalizedData.Name) + $AcctRg = $AzAutoAcctItem.($LocalizedData.ResourceGroup) + Section -Style NOTOCHeading5 -ExcludeFromTOC $AcctName { + $TableParams = @{ + Name = "$($LocalizedData.TableHeading) - $AcctName" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AzAutoAcctItem | Table @TableParams + + $AzRunbooks = Get-AzAutomationRunbook -AutomationAccountName $AcctName -ResourceGroupName $AcctRg -ErrorAction SilentlyContinue | Sort-Object Name + if ($AzRunbooks) { + Section -Style NOTOCHeading6 -ExcludeFromTOC $LocalizedData.RunbooksHeading { + $RunbookInfo = @() + foreach ($Runbook in $AzRunbooks) { + $InObj = [Ordered]@{ + $LocalizedData.Name = $Runbook.Name + $LocalizedData.RunbookType = $Runbook.RunbookType + $LocalizedData.State = $Runbook.State + $LocalizedData.LastModified = $Runbook.LastModifiedTime + } + $RunbookInfo += [PSCustomObject]$InObj + } + $TableParams = @{ + Name = "$($LocalizedData.RunbooksHeading) - $AcctName" + List = $false + ColumnWidths = 35, 20, 20, 25 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $RunbookInfo | Table @TableParams + } + } + + $AzVariables = Get-AzAutomationVariable -AutomationAccountName $AcctName -ResourceGroupName $AcctRg -ErrorAction SilentlyContinue | Sort-Object Name + if ($AzVariables) { + Section -Style NOTOCHeading6 -ExcludeFromTOC $LocalizedData.VariablesHeading { + $VariableInfo = @() + foreach ($Variable in $AzVariables) { + $InObj = [Ordered]@{ + $LocalizedData.Name = $Variable.Name + $LocalizedData.Encrypted = if ($Variable.Encrypted) { $LocalizedData.Yes } else { $LocalizedData.No } + $LocalizedData.Description = if ($Variable.Description) { $Variable.Description } else { $LocalizedData.None } + } + $VariableInfo += [PSCustomObject]$InObj + } + $TableParams = @{ + Name = "$($LocalizedData.VariablesHeading) - $AcctName" + List = $false + ColumnWidths = 35, 15, 50 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $VariableInfo | Table @TableParams + } + } + + $AzSchedules = Get-AzAutomationSchedule -AutomationAccountName $AcctName -ResourceGroupName $AcctRg -ErrorAction SilentlyContinue | Sort-Object Name + if ($AzSchedules) { + Section -Style NOTOCHeading6 -ExcludeFromTOC $LocalizedData.SchedulesHeading { + $ScheduleInfo = @() + foreach ($Schedule in $AzSchedules) { + $InObj = [Ordered]@{ + $LocalizedData.Name = $Schedule.Name + $LocalizedData.Enabled = if ($Schedule.IsEnabled) { $LocalizedData.Yes } else { $LocalizedData.No } + $LocalizedData.Frequency = $Schedule.Frequency + $LocalizedData.NextRun = $Schedule.NextRun + } + $ScheduleInfo += [PSCustomObject]$InObj + } + $TableParams = @{ + Name = "$($LocalizedData.SchedulesHeading) - $AcctName" + List = $false + ColumnWidths = 30, 15, 20, 35 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $ScheduleInfo | Table @TableParams + } + } + + $AzCredentials = Get-AzAutomationCredential -AutomationAccountName $AcctName -ResourceGroupName $AcctRg -ErrorAction SilentlyContinue | Sort-Object Name + if ($AzCredentials) { + Section -Style NOTOCHeading6 -ExcludeFromTOC $LocalizedData.CredentialsHeading { + $CredentialInfo = @() + foreach ($Credential in $AzCredentials) { + $InObj = [Ordered]@{ + $LocalizedData.Name = $Credential.Name + $LocalizedData.UserName = $Credential.UserName + } + $CredentialInfo += [PSCustomObject]$InObj + } + $TableParams = @{ + Name = "$($LocalizedData.CredentialsHeading) - $AcctName" + List = $false + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $CredentialInfo | Table @TableParams + } + } + } + } + } else { + Paragraph ($LocalizedData.ParagraphSummary -f $AzSubscription.Name) + BlankLine + $TableParams = @{ + Name = "$($LocalizedData.TableHeading) - $($AzSubscription.Name)" + List = $false + Columns = $LocalizedData.Name, $LocalizedData.ResourceGroup, $LocalizedData.Location, $LocalizedData.State + ColumnWidths = 35, 30, 20, 15 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AzAutomationAccountInfo | Table @TableParams + } + } + } + } + } catch { + Write-PScriboMessage -IsWarning "$($LocalizedData.ErrorMessage) $($_.Exception.Message)" + } + } + + end {} +} diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzAvailabilitySet.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzAvailabilitySet.ps1 similarity index 100% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzAvailabilitySet.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzAvailabilitySet.ps1 diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzBastion.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzBastion.ps1 similarity index 100% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzBastion.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzBastion.ps1 diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzDataCollectionRule.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzDataCollectionRule.ps1 new file mode 100644 index 0000000..adff8c8 --- /dev/null +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzDataCollectionRule.ps1 @@ -0,0 +1,162 @@ +function Get-AbrAzDataCollectionRule { + <# + .SYNOPSIS + Used by As Built Report to retrieve Azure Data Collection Rule information + .DESCRIPTION + Documents the configuration of Azure Data Collection Rules including data sources, + Log Analytics destinations, and data flows. + .NOTES + Version: 0.1.0 + Author: Tim Carman + Twitter: @tpcarman + Github: tpcarman + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param () + + begin { + $LocalizedData = $reportTranslate.GetAbrAzDataCollectionRule + Write-PScriboMessage ($LocalizedData.InfoLevel -f $InfoLevel.DataCollectionRule) + } + + process { + try { + if ($InfoLevel.DataCollectionRule -ge 1) { + $AzDcrs = Get-AzDataCollectionRule -ErrorAction SilentlyContinue | Sort-Object Name + if ($AzDcrs) { + Write-PScriboMessage $LocalizedData.Collecting + Section -Style Heading4 $LocalizedData.Heading { + if ($Options.ShowSectionInfo) { + Paragraph $LocalizedData.SectionInfo + BlankLine + } + + $AzDcrInfo = @() + foreach ($AzDcr in $AzDcrs) { + $DataSourceTypes = @() + if ($AzDcr.DataSourcePerformanceCounter) { $DataSourceTypes += $LocalizedData.PerformanceCounters } + if ($AzDcr.DataSourceWindowsEventLog) { $DataSourceTypes += $LocalizedData.WindowsEventLogs } + if ($AzDcr.DataSourceSyslog) { $DataSourceTypes += $LocalizedData.Syslog } + if ($AzDcr.DataSourceExtension) { $DataSourceTypes += $LocalizedData.Extensions } + if ($AzDcr.DataSourceLogFile) { $DataSourceTypes += $LocalizedData.LogFiles } + $DataSourceSummary = if ($DataSourceTypes) { $DataSourceTypes -join ', ' } else { $LocalizedData.None } + + $DestinationCount = if ($AzDcr.DestinationLogAnalytic) { $AzDcr.DestinationLogAnalytic.Count } else { 0 } + + $InObj = [Ordered]@{ + $LocalizedData.Name = $AzDcr.Name + $LocalizedData.ResourceGroup = $AzDcr.ResourceGroupName + $LocalizedData.Location = $AzLocationLookup."$($AzDcr.Location)" + $LocalizedData.Subscription = "$($AzSubscriptionLookup.(($AzDcr.Id).split('/')[2]))" + $LocalizedData.SubscriptionID = ($AzDcr.Id).split('/')[2] + $LocalizedData.Description = if ($AzDcr.Description) { $AzDcr.Description } else { $LocalizedData.None } + $LocalizedData.DataSources = $DataSourceSummary + $LocalizedData.LogAnalyticsDestinations = $DestinationCount + $LocalizedData.ProvisioningState = $AzDcr.ProvisioningState + } + + if ($Options.ShowTags) { + $InObj[$LocalizedData.Tags] = if ($null -eq $AzDcr.Tag -or $AzDcr.Tag.Count -eq 0) { + $LocalizedData.None + } else { + ($AzDcr.Tag.Keys | ForEach-Object { "$_`:`t$($AzDcr.Tag[$_])" }) -join [Environment]::NewLine + } + } + + $AzDcrInfo += [PSCustomObject]$InObj + } + + if ($Healthcheck.DataCollectionRule.ProvisioningState) { + $AzDcrInfo | Where-Object { $_.$($LocalizedData.ProvisioningState) -ne 'Succeeded' } | Set-Style -Style Critical -Property $LocalizedData.ProvisioningState + } + + if ($InfoLevel.DataCollectionRule -ge 2) { + Paragraph ($LocalizedData.ParagraphDetail -f $AzSubscription.Name) + foreach ($AzDcrItem in $AzDcrInfo) { + $DcrName = $AzDcrItem.($LocalizedData.Name) + $DcrRg = $AzDcrItem.($LocalizedData.ResourceGroup) + $FullDcr = $AzDcrs | Where-Object { $_.Name -eq $DcrName -and $_.ResourceGroupName -eq $DcrRg } + Section -Style NOTOCHeading5 -ExcludeFromTOC $DcrName { + $TableParams = @{ + Name = "$($LocalizedData.TableHeading) - $DcrName" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AzDcrItem | Table @TableParams + + if ($FullDcr.DestinationLogAnalytic) { + Section -Style NOTOCHeading6 -ExcludeFromTOC $LocalizedData.Destinations { + $DestInfo = @() + foreach ($Dest in $FullDcr.DestinationLogAnalytic) { + $InObj = [Ordered]@{ + $LocalizedData.DestinationName = $Dest.Name + $LocalizedData.WorkspaceId = $Dest.WorkspaceResourceId + } + $DestInfo += [PSCustomObject]$InObj + } + $TableParams = @{ + Name = "$($LocalizedData.Destinations) - $DcrName" + List = $false + ColumnWidths = 35, 65 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $DestInfo | Table @TableParams + } + } + + if ($FullDcr.DataFlow) { + Section -Style NOTOCHeading6 -ExcludeFromTOC $LocalizedData.DataFlows { + $FlowInfo = @() + foreach ($Flow in $FullDcr.DataFlow) { + $InObj = [Ordered]@{ + $LocalizedData.Streams = ($Flow.Stream -join ', ') + $LocalizedData.Destinations = ($Flow.Destination -join ', ') + } + $FlowInfo += [PSCustomObject]$InObj + } + $TableParams = @{ + Name = "$($LocalizedData.DataFlows) - $DcrName" + List = $false + ColumnWidths = 55, 45 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $FlowInfo | Table @TableParams + } + } + } + } + } else { + Paragraph ($LocalizedData.ParagraphSummary -f $AzSubscription.Name) + BlankLine + $TableParams = @{ + Name = "$($LocalizedData.TableHeading) - $($AzSubscription.Name)" + List = $false + Columns = $LocalizedData.Name, $LocalizedData.ResourceGroup, $LocalizedData.Location, $LocalizedData.LogAnalyticsDestinations, $LocalizedData.ProvisioningState + ColumnWidths = 25, 20, 15, 25, 15 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AzDcrInfo | Table @TableParams + } + } + } + } + } catch { + Write-PScriboMessage -IsWarning "$($LocalizedData.ErrorMessage) $($_.Exception.Message)" + } + } + + end {} +} diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzDdosProtectionPlan.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzDdosProtectionPlan.ps1 new file mode 100644 index 0000000..8b06332 --- /dev/null +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzDdosProtectionPlan.ps1 @@ -0,0 +1,145 @@ +function Get-AbrAzDdosProtectionPlan { + <# + .SYNOPSIS + Used by As Built Report to retrieve Azure DDoS Protection Plan information + .DESCRIPTION + Documents the configuration of Azure DDoS Protection Plans including protected + virtual networks and provisioning state. + .NOTES + Version: 0.1.0 + Author: Tim Carman + Twitter: @tpcarman + Github: tpcarman + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param () + + begin { + $LocalizedData = $reportTranslate.GetAbrAzDdosProtectionPlan + Write-PScriboMessage ($LocalizedData.InfoLevel -f $InfoLevel.DdosProtectionPlan) + } + + process { + try { + if ($InfoLevel.DdosProtectionPlan -ge 1) { + $AzDdosPlans = Get-AzDdosProtectionPlan -ErrorAction SilentlyContinue | Sort-Object Name + if ($AzDdosPlans) { + Write-PScriboMessage $LocalizedData.Collecting + Section -Style Heading4 $LocalizedData.Heading { + if ($Options.ShowSectionInfo) { + Paragraph $LocalizedData.SectionInfo + BlankLine + } + + $LockMap = @{} + $AllLocks = Get-AzResourceLock -ErrorAction SilentlyContinue + foreach ($Lock in $AllLocks) { + $Key = $Lock.ResourceId.ToLower() + if (-not $LockMap.ContainsKey($Key)) { $LockMap[$Key] = @() } + $LockMap[$Key] += $Lock + } + + $AzDdosPlanInfo = @() + foreach ($AzDdosPlan in $AzDdosPlans) { + $ProtectedVNetCount = if ($AzDdosPlan.VirtualNetworks) { $AzDdosPlan.VirtualNetworks.Count } else { 0 } + $InObj = [Ordered]@{ + $LocalizedData.Name = $AzDdosPlan.Name + $LocalizedData.ResourceGroup = $AzDdosPlan.ResourceGroupName + $LocalizedData.Location = $AzLocationLookup."$($AzDdosPlan.Location)" + $LocalizedData.Subscription = "$($AzSubscriptionLookup.(($AzDdosPlan.Id).split('/')[2]))" + $LocalizedData.SubscriptionID = ($AzDdosPlan.Id).split('/')[2] + $LocalizedData.ProtectedVirtualNetworks = $ProtectedVNetCount + $LocalizedData.ProvisioningState = $AzDdosPlan.ProvisioningState + } + + $InObj[$LocalizedData.Locks] = $( + $rl = $LockMap[$AzDdosPlan.Id.ToLower()] + if ($rl) { ($rl | ForEach-Object { "$($_.Name) ($($_.Properties.Level))" }) -join [Environment]::NewLine } + else { $LocalizedData.None } + ) + + if ($Options.ShowTags) { + $InObj[$LocalizedData.Tags] = if ($null -eq $AzDdosPlan.Tags -or $AzDdosPlan.Tags.Count -eq 0) { + $LocalizedData.None + } else { + ($AzDdosPlan.Tags.Keys | ForEach-Object { "$_`:`t$($AzDdosPlan.Tags[$_])" }) -join [Environment]::NewLine + } + } + + $AzDdosPlanInfo += [PSCustomObject]$InObj + } + + if ($Healthcheck.DdosProtectionPlan.ProvisioningState) { + $AzDdosPlanInfo | Where-Object { $_.$($LocalizedData.ProvisioningState) -ne 'Succeeded' } | Set-Style -Style Critical -Property $LocalizedData.ProvisioningState + } + + if ($InfoLevel.DdosProtectionPlan -ge 2) { + Paragraph ($LocalizedData.ParagraphDetail -f $AzSubscription.Name) + foreach ($AzDdosPlan in $AzDdosPlanInfo) { + $PlanName = $AzDdosPlan.($LocalizedData.Name) + $PlanRg = $AzDdosPlan.($LocalizedData.ResourceGroup) + Section -Style NOTOCHeading5 -ExcludeFromTOC $PlanName { + $TableParams = @{ + Name = "$($LocalizedData.TableHeading) - $PlanName" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AzDdosPlan | Table @TableParams + + $FullPlan = $AzDdosPlans | Where-Object { $_.Name -eq $PlanName -and $_.ResourceGroupName -eq $PlanRg } + if ($FullPlan -and $FullPlan.VirtualNetworks) { + Section -Style NOTOCHeading6 -ExcludeFromTOC $LocalizedData.ProtectedVirtualNetworks { + $VNetInfo = @() + foreach ($VNet in $FullPlan.VirtualNetworks) { + $VNetIdParts = $VNet.Id.split('/') + $InObj = [Ordered]@{ + $LocalizedData.VirtualNetworkName = $VNetIdParts[-1] + $LocalizedData.ResourceGroup = $VNetIdParts[4] + $LocalizedData.Subscription = "$($AzSubscriptionLookup.($VNetIdParts[2]))" + } + $VNetInfo += [PSCustomObject]$InObj + } + $TableParams = @{ + Name = "$($LocalizedData.ProtectedVirtualNetworks) - $PlanName" + List = $false + ColumnWidths = 40, 35, 25 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $VNetInfo | Table @TableParams + } + } + } + } + } else { + Paragraph ($LocalizedData.ParagraphSummary -f $AzSubscription.Name) + BlankLine + $TableParams = @{ + Name = "$($LocalizedData.TableHeading) - $($AzSubscription.Name)" + List = $false + Columns = $LocalizedData.Name, $LocalizedData.ResourceGroup, $LocalizedData.Location, $LocalizedData.ProtectedVirtualNetworks, $LocalizedData.ProvisioningState + ColumnWidths = 25, 20, 15, 20, 20 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AzDdosPlanInfo | Table @TableParams + } + } + } + } + } catch { + Write-PScriboMessage -IsWarning "$($LocalizedData.ErrorMessage) $($_.Exception.Message)" + } + } + + end {} +} diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzDesktopVirtualization.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzDesktopVirtualization.ps1 similarity index 100% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzDesktopVirtualization.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzDesktopVirtualization.ps1 diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzDiagnosticSetting.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzDiagnosticSetting.ps1 new file mode 100644 index 0000000..e349246 --- /dev/null +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzDiagnosticSetting.ps1 @@ -0,0 +1,124 @@ +function Get-AbrAzDiagnosticSetting { + <# + .SYNOPSIS + Used by As Built Report to retrieve Azure Diagnostic Setting information + .DESCRIPTION + Documents the configuration of Azure Diagnostic Settings across resources, including + Log Analytics workspace, storage account, and Event Hub destinations. + .NOTES + Version: 0.1.0 + Author: Tim Carman + Twitter: @tpcarman + Github: tpcarman + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param () + + begin { + $LocalizedData = $reportTranslate.GetAbrAzDiagnosticSetting + Write-PScriboMessage ($LocalizedData.InfoLevel -f $InfoLevel.DiagnosticSetting) + } + + process { + try { + if ($InfoLevel.DiagnosticSetting -ge 1) { + Write-PScriboMessage $LocalizedData.Collecting + $AzResources = Get-AzResource -ErrorAction SilentlyContinue | Sort-Object Name + + $DiagSettingsData = @() + foreach ($Resource in $AzResources) { + $Settings = Get-AzDiagnosticSetting -ResourceId $Resource.ResourceId -WarningAction SilentlyContinue -ErrorAction SilentlyContinue + foreach ($Setting in $Settings) { + $EnabledLogCount = ($Setting.Log | Where-Object { $_.Enabled }).Count + $MetricsEnabled = ($Setting.Metric | Where-Object { $_.Enabled }).Count -gt 0 + + $WorkspaceName = if ($Setting.WorkspaceId) { + ($Setting.WorkspaceId).split('/')[-1] + } else { + $LocalizedData.None + } + + $StorageAccountName = if ($Setting.StorageAccountId) { + ($Setting.StorageAccountId).split('/')[-1] + } else { + $LocalizedData.None + } + + $EventHubName = if ($Setting.EventHubAuthorizationRuleId) { + ($Setting.EventHubAuthorizationRuleId).split('/')[-3] + } else { + $LocalizedData.None + } + + $InObj = [Ordered]@{ + $LocalizedData.ResourceName = $Resource.Name + $LocalizedData.ResourceType = $Resource.ResourceType + $LocalizedData.ResourceGroup = $Resource.ResourceGroupName + $LocalizedData.Name = $Setting.Name + $LocalizedData.LogAnalyticsWorkspace = $WorkspaceName + $LocalizedData.StorageAccount = $StorageAccountName + $LocalizedData.EventHub = $EventHubName + $LocalizedData.LogCategoriesEnabled = $EnabledLogCount + $LocalizedData.MetricsEnabled = if ($MetricsEnabled) { $LocalizedData.Yes } else { $LocalizedData.No } + } + + $DiagSettingsData += [PSCustomObject]$InObj + } + } + + if ($DiagSettingsData) { + Section -Style Heading4 $LocalizedData.Heading { + if ($Options.ShowSectionInfo) { + Paragraph $LocalizedData.SectionInfo + BlankLine + } + + if ($Healthcheck.DiagnosticSetting.NoLogsEnabled) { + $DiagSettingsData | Where-Object { $_.$($LocalizedData.LogCategoriesEnabled) -eq 0 } | Set-Style -Style Warning -Property $LocalizedData.LogCategoriesEnabled + } + + if ($InfoLevel.DiagnosticSetting -ge 2) { + Paragraph ($LocalizedData.ParagraphDetail -f $AzSubscription.Name) + BlankLine + foreach ($DiagSetting in $DiagSettingsData) { + $SectionTitle = "$($DiagSetting.($LocalizedData.ResourceName)) - $($DiagSetting.($LocalizedData.Name))" + Section -Style NOTOCHeading5 -ExcludeFromTOC $SectionTitle { + $TableParams = @{ + Name = "$($LocalizedData.TableHeading) - $SectionTitle" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $DiagSetting | Table @TableParams + } + } + } else { + Paragraph ($LocalizedData.ParagraphSummary -f $AzSubscription.Name) + BlankLine + $TableParams = @{ + Name = "$($LocalizedData.TableHeading) - $($AzSubscription.Name)" + List = $false + Columns = $LocalizedData.ResourceName, $LocalizedData.ResourceGroup, $LocalizedData.Name, $LocalizedData.LogCategoriesEnabled, $LocalizedData.MetricsEnabled + ColumnWidths = 25, 20, 25, 15, 15 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $DiagSettingsData | Table @TableParams + } + } + } + } + } catch { + Write-PScriboMessage -IsWarning "$($LocalizedData.ErrorMessage) $($_.Exception.Message)" + } + } + + end {} +} diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzDnsForwardingRuleset.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzDnsForwardingRuleset.ps1 new file mode 100644 index 0000000..fbd203b --- /dev/null +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzDnsForwardingRuleset.ps1 @@ -0,0 +1,186 @@ +function Get-AbrAzDnsForwardingRuleset { + <# + .SYNOPSIS + Used by As Built Report to retrieve Azure DNS Forwarding Ruleset information + .DESCRIPTION + Documents the configuration of Azure DNS Forwarding Rulesets, including forwarding rules + with target DNS servers and virtual network link associations. + .NOTES + Version: 0.1.0 + Author: Tim Carman + Twitter: @tpcarman + Github: tpcarman + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param () + + begin { + $LocalizedData = $reportTranslate.GetAbrAzDnsForwardingRuleset + Write-PScriboMessage ($LocalizedData.InfoLevel -f $InfoLevel.DnsForwardingRuleset) + } + + process { + try { + if ($InfoLevel.DnsForwardingRuleset -ge 1) { + $AzDnsForwardingRulesets = Get-AzDnsForwardingRuleset -ErrorAction SilentlyContinue | Sort-Object Name + if ($AzDnsForwardingRulesets) { + Write-PScriboMessage $LocalizedData.Collecting + + # Pre-collect forwarding rules and VNet links per ruleset + $ForwardingRulesMap = @{} + $VNetLinksMap = @{} + foreach ($AzRuleset in $AzDnsForwardingRulesets) { + $RG = ($AzRuleset.Id).split('/')[4] + $ForwardingRulesMap[$AzRuleset.Name] = Get-AzDnsForwardingRule -DnsForwardingRulesetName $AzRuleset.Name -ResourceGroupName $RG -ErrorAction SilentlyContinue + $VNetLinksMap[$AzRuleset.Name] = Get-AzDnsForwardingRulesetVirtualNetworkLink -DnsForwardingRulesetName $AzRuleset.Name -ResourceGroupName $RG -ErrorAction SilentlyContinue + } + + Section -Style Heading4 $LocalizedData.Heading { + if ($Options.ShowSectionInfo) { + Paragraph $LocalizedData.SectionInfo + BlankLine + } + + $AzRulesetInfo = @() + foreach ($AzRuleset in $AzDnsForwardingRulesets) { + $RuleCount = if ($ForwardingRulesMap[$AzRuleset.Name]) { @($ForwardingRulesMap[$AzRuleset.Name]).Count } else { 0 } + $LinkCount = if ($VNetLinksMap[$AzRuleset.Name]) { @($VNetLinksMap[$AzRuleset.Name]).Count } else { 0 } + $OutboundEndpoints = if ($AzRuleset.DnsResolverOutboundEndpoint -and $AzRuleset.DnsResolverOutboundEndpoint.Count -gt 0) { + ($AzRuleset.DnsResolverOutboundEndpoint | ForEach-Object { $_.Id.split('/')[-1] }) -join [Environment]::NewLine + } else { + $LocalizedData.None + } + $InObj = [Ordered]@{ + $LocalizedData.Name = $AzRuleset.Name + $LocalizedData.ResourceGroup = ($AzRuleset.Id).split('/')[4] + $LocalizedData.Location = $AzLocationLookup."$($AzRuleset.Location)" + $LocalizedData.Subscription = "$($AzSubscriptionLookup.(($AzRuleset.Id).split('/')[2]))" + $LocalizedData.SubscriptionID = ($AzRuleset.Id).split('/')[2] + $LocalizedData.ForwardingRules = $RuleCount + $LocalizedData.VirtualNetworkLinks = $LinkCount + $LocalizedData.OutboundEndpoints = $OutboundEndpoints + $LocalizedData.ProvisioningState = $AzRuleset.ProvisioningState + } + + if ($Options.ShowTags) { + $InObj[$LocalizedData.Tags] = if ($null -eq $AzRuleset.Tag -or $AzRuleset.Tag.Count -eq 0) { + $LocalizedData.None + } else { + ($AzRuleset.Tag.Keys | ForEach-Object { "$_`:`t$($AzRuleset.Tag.AdditionalProperties[$_])" }) -join [Environment]::NewLine + } + } + + $AzRulesetInfo += [PSCustomObject]$InObj + } + + if ($Healthcheck.DnsForwardingRuleset.ProvisioningState) { + $AzRulesetInfo | Where-Object { $_.$($LocalizedData.ProvisioningState) -ne 'Succeeded' } | Set-Style -Style Critical -Property $LocalizedData.ProvisioningState + } + + if ($InfoLevel.DnsForwardingRuleset -ge 2) { + Paragraph ($LocalizedData.ParagraphDetail -f $AzSubscription.Name) + foreach ($AzRulesetItem in $AzRulesetInfo) { + $RulesetName = $AzRulesetItem.($LocalizedData.Name) + Section -Style NOTOCHeading5 -ExcludeFromTOC $RulesetName { + $TableParams = @{ + Name = "$($LocalizedData.TableHeading) - $RulesetName" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AzRulesetItem | Table @TableParams + + # Forwarding Rules sub-section + $Rules = $ForwardingRulesMap[$RulesetName] + if ($Rules) { + Section -Style NOTOCHeading6 -ExcludeFromTOC $LocalizedData.ForwardingRulesHeading { + $RuleInfo = @() + foreach ($Rule in $Rules) { + $TargetServers = if ($Rule.TargetDnsServer -and $Rule.TargetDnsServer.Count -gt 0) { + ($Rule.TargetDnsServer | ForEach-Object { "$($_.IPAddress):$($_.Port)" }) -join [Environment]::NewLine + } else { + $LocalizedData.None + } + $InObj = [Ordered]@{ + $LocalizedData.RuleName = $Rule.Name + $LocalizedData.DomainName = $Rule.DomainName + $LocalizedData.TargetServers = $TargetServers + $LocalizedData.RuleState = $Rule.DnsForwardingRuleState + $LocalizedData.ProvisioningState = $Rule.ProvisioningState + } + $RuleInfo += [PSCustomObject]$InObj + } + + if ($Healthcheck.DnsForwardingRuleset.ForwardingRuleState) { + $RuleInfo | Where-Object { $_.$($LocalizedData.RuleState) -ne 'Enabled' } | Set-Style -Style Warning -Property $LocalizedData.RuleState + } + + $TableParams = @{ + Name = "$($LocalizedData.ForwardingRulesHeading) - $RulesetName" + List = $false + ColumnWidths = 20, 30, 30, 10, 10 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $RuleInfo | Table @TableParams + } + } + + # Virtual Network Links sub-section + $VNetLinks = $VNetLinksMap[$RulesetName] + if ($VNetLinks) { + Section -Style NOTOCHeading6 -ExcludeFromTOC $LocalizedData.VNetLinksHeading { + $LinkInfo = @() + foreach ($Link in $VNetLinks) { + $InObj = [Ordered]@{ + $LocalizedData.LinkName = $Link.Name + $LocalizedData.VirtualNetwork = $Link.VirtualNetworkId.split('/')[-1] + $LocalizedData.ProvisioningState = $Link.ProvisioningState + } + $LinkInfo += [PSCustomObject]$InObj + } + + $TableParams = @{ + Name = "$($LocalizedData.VNetLinksHeading) - $RulesetName" + List = $false + ColumnWidths = 30, 50, 20 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $LinkInfo | Table @TableParams + } + } + } + } + } else { + Paragraph ($LocalizedData.ParagraphSummary -f $AzSubscription.Name) + BlankLine + $TableParams = @{ + Name = "$($LocalizedData.TableHeading) - $($AzSubscription.Name)" + List = $false + Columns = $LocalizedData.Name, $LocalizedData.Location, $LocalizedData.ForwardingRules, $LocalizedData.VirtualNetworkLinks, $LocalizedData.OutboundEndpoints, $LocalizedData.ProvisioningState + ColumnWidths = 20, 15, 15, 15, 20, 15 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AzRulesetInfo | Table @TableParams + } + } + } + } + } catch { + Write-PScriboMessage -IsWarning "$($LocalizedData.ErrorMessage) $($_.Exception.Message)" + } + } + + end {} +} diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzDnsPrivateResolver.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzDnsPrivateResolver.ps1 similarity index 100% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzDnsPrivateResolver.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzDnsPrivateResolver.ps1 diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzExpressRouteCircuit.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzExpressRouteCircuit.ps1 similarity index 100% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzExpressRouteCircuit.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzExpressRouteCircuit.ps1 diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzFirewall.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzFirewall.ps1 similarity index 90% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzFirewall.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzFirewall.ps1 index 3df06d2..c07e95c 100644 --- a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzFirewall.ps1 +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzFirewall.ps1 @@ -34,6 +34,14 @@ function Get-AbrAzFirewall { Paragraph $LocalizedData.SectionInfo BlankLine } + $LockMap = @{} + $AllLocks = Get-AzResourceLock -ErrorAction SilentlyContinue + foreach ($Lock in $AllLocks) { + $Key = $Lock.ResourceId.ToLower() + if (-not $LockMap.ContainsKey($Key)) { $LockMap[$Key] = @() } + $LockMap[$Key] += $Lock + } + $AzFirewallInfo = @() foreach ($AzFirewall in $AzFirewalls) { $InObj = [Ordered]@{ @@ -74,6 +82,12 @@ function Get-AbrAzFirewall { $InObj[$LocalizedData.ApplicationRuleCollections] = $AzFirewall.ApplicationRuleCollections.Count } + $InObj[$LocalizedData.Locks] = $( + $rl = $LockMap[$AzFirewall.Id.ToLower()] + if ($rl) { ($rl | ForEach-Object { "$($_.Name) ($($_.Properties.Level))" }) -join [Environment]::NewLine } + else { $LocalizedData.None } + ) + if ($Options.ShowTags) { $InObj[$LocalizedData.Tags] = if ([string]::IsNullOrEmpty($AzFirewall.Tag)) { $LocalizedData.None diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzFirewallNatRule.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzFirewallNatRule.ps1 similarity index 100% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzFirewallNatRule.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzFirewallNatRule.ps1 diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzFirewallNetworkRule.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzFirewallNetworkRule.ps1 similarity index 100% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzFirewallNetworkRule.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzFirewallNetworkRule.ps1 diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzFirewallPolicy.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzFirewallPolicy.ps1 similarity index 100% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzFirewallPolicy.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzFirewallPolicy.ps1 diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzIpGroup.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzIpGroup.ps1 similarity index 100% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzIpGroup.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzIpGroup.ps1 diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzKeyVault.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzKeyVault.ps1 similarity index 90% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzKeyVault.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzKeyVault.ps1 index a9b48d8..4463df8 100644 --- a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzKeyVault.ps1 +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzKeyVault.ps1 @@ -36,6 +36,14 @@ function Get-AbrAzKeyVault { } Paragraph ($LocalizedData.ParagraphSummary -f $AzSubscription.Name) BlankLine + $LockMap = @{} + $AllLocks = Get-AzResourceLock -ErrorAction SilentlyContinue + foreach ($Lock in $AllLocks) { + $Key = $Lock.ResourceId.ToLower() + if (-not $LockMap.ContainsKey($Key)) { $LockMap[$Key] = @() } + $LockMap[$Key] += $Lock + } + $AzKeyVaultInfo = @() foreach ($AzKeyVault in $AzKeyVaults) { $AzKeyVault = Get-AzKeyVault -Name $AzKeyVault.VaultName @@ -84,6 +92,12 @@ function Get-AbrAzKeyVault { }) } + $InObj[$LocalizedData.Locks] = $( + $rl = $LockMap[$AzKeyVault.ResourceId.ToLower()] + if ($rl) { ($rl | ForEach-Object { "$($_.Name) ($($_.Properties.Level))" }) -join [Environment]::NewLine } + else { $LocalizedData.None } + ) + if ($Options.ShowTags) { $InObj[$LocalizedData.Tags] = if ([string]::IsNullOrEmpty($AzKeyVault.Tags)) { $LocalizedData.None diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzLbBackendPool.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzLbBackendPool.ps1 similarity index 100% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzLbBackendPool.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzLbBackendPool.ps1 diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzLbFrontendIpConfig.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzLbFrontendIpConfig.ps1 similarity index 100% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzLbFrontendIpConfig.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzLbFrontendIpConfig.ps1 diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzLbHealthProbe.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzLbHealthProbe.ps1 similarity index 100% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzLbHealthProbe.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzLbHealthProbe.ps1 diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzLbInboundNatPool.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzLbInboundNatPool.ps1 similarity index 100% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzLbInboundNatPool.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzLbInboundNatPool.ps1 diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzLbLoadBalancingRule.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzLbLoadBalancingRule.ps1 similarity index 100% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzLbLoadBalancingRule.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzLbLoadBalancingRule.ps1 diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzLoadBalancer.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzLoadBalancer.ps1 similarity index 100% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzLoadBalancer.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzLoadBalancer.ps1 diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzLogAnalyticsWorkspace.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzLogAnalyticsWorkspace.ps1 similarity index 90% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzLogAnalyticsWorkspace.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzLogAnalyticsWorkspace.ps1 index 16a6d24..1ed6557 100644 --- a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzLogAnalyticsWorkspace.ps1 +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzLogAnalyticsWorkspace.ps1 @@ -34,6 +34,14 @@ function Get-AbrAzLogAnalyticsWorkspace { Paragraph $LocalizedData.SectionInfo BlankLine } + $LockMap = @{} + $AllLocks = Get-AzResourceLock -ErrorAction SilentlyContinue + foreach ($Lock in $AllLocks) { + $Key = $Lock.ResourceId.ToLower() + if (-not $LockMap.ContainsKey($Key)) { $LockMap[$Key] = @() } + $LockMap[$Key] += $Lock + } + $AzLogAnalyticsWorkspaceInfo = @() foreach ($AzLogAnalyticsWorkspace in $AzLogAnalyticsWorkspaces) { $InObj = [Ordered]@{ @@ -63,6 +71,12 @@ function Get-AbrAzLogAnalyticsWorkspace { } } + $InObj[$LocalizedData.Locks] = $( + $rl = $LockMap[$AzLogAnalyticsWorkspace.ResourceId.ToLower()] + if ($rl) { ($rl | ForEach-Object { "$($_.Name) ($($_.Properties.Level))" }) -join [Environment]::NewLine } + else { $LocalizedData.None } + ) + if ($Options.ShowTags) { $InObj[$LocalizedData.Tags] = if ([string]::IsNullOrEmpty($AzLogAnalyticsWorkspace.Tags)) { $LocalizedData.None diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzMaintenanceConfiguration.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzMaintenanceConfiguration.ps1 new file mode 100644 index 0000000..fdb56ed --- /dev/null +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzMaintenanceConfiguration.ps1 @@ -0,0 +1,132 @@ +function Get-AbrAzMaintenanceConfiguration { + <# + .SYNOPSIS + Used by As Built Report to retrieve Azure Maintenance Configuration information + .DESCRIPTION + Documents the configuration of Azure Maintenance Configurations, including scope, + maintenance window, recurrence, timezone, and visibility settings. + .NOTES + Version: 0.1.0 + Author: Tim Carman + Twitter: @tpcarman + Github: tpcarman + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param () + + begin { + $LocalizedData = $reportTranslate.GetAbrAzMaintenanceConfiguration + Write-PScriboMessage ($LocalizedData.InfoLevel -f $InfoLevel.MaintenanceConfiguration) + } + + process { + try { + if ($InfoLevel.MaintenanceConfiguration -ge 1) { + $AzMaintenanceConfigs = Get-AzMaintenanceConfiguration -ErrorAction SilentlyContinue | Sort-Object Name + if ($AzMaintenanceConfigs) { + Write-PScriboMessage $LocalizedData.Collecting + + Section -Style Heading4 $LocalizedData.Heading { + if ($Options.ShowSectionInfo) { + Paragraph $LocalizedData.SectionInfo + BlankLine + } + + $AzMcInfo = @() + foreach ($AzMc in $AzMaintenanceConfigs) { + $ResourceGroup = ($AzMc.Id).split('/')[4] + $StartDateTime = if ($AzMc.MaintenanceWindow.StartDateTime) { + $AzMc.MaintenanceWindow.StartDateTime + } else { + $LocalizedData.NotConfigured + } + $ExpirationDateTime = if ($AzMc.MaintenanceWindow.ExpirationDateTime) { + $AzMc.MaintenanceWindow.ExpirationDateTime + } else { + $LocalizedData.NoExpiry + } + $Duration = if ($AzMc.MaintenanceWindow.Duration) { + $AzMc.MaintenanceWindow.Duration + } else { + $LocalizedData.NotConfigured + } + $RecurEvery = if ($AzMc.MaintenanceWindow.RecurEvery) { + $AzMc.MaintenanceWindow.RecurEvery + } else { + $LocalizedData.NotConfigured + } + $TimeZone = if ($AzMc.MaintenanceWindow.TimeZone) { + $AzMc.MaintenanceWindow.TimeZone + } else { + $LocalizedData.NotConfigured + } + $InObj = [Ordered]@{ + $LocalizedData.Name = $AzMc.Name + $LocalizedData.ResourceGroup = $ResourceGroup + $LocalizedData.Location = $AzLocationLookup."$($AzMc.Location)" + $LocalizedData.Subscription = "$($AzSubscriptionLookup.(($AzMc.Id).split('/')[2]))" + $LocalizedData.SubscriptionID = ($AzMc.Id).split('/')[2] + $LocalizedData.Scope = $AzMc.MaintenanceScope + $LocalizedData.Visibility = $AzMc.Visibility + $LocalizedData.StartDateTime = $StartDateTime + $LocalizedData.ExpirationDateTime = $ExpirationDateTime + $LocalizedData.Duration = $Duration + $LocalizedData.RecurEvery = $RecurEvery + $LocalizedData.TimeZone = $TimeZone + } + + if ($Options.ShowTags) { + $InObj[$LocalizedData.Tags] = if ($null -eq $AzMc.Tag -or $AzMc.Tag.Count -eq 0) { + $LocalizedData.None + } else { + ($AzMc.Tag.GetEnumerator() | ForEach-Object { "$($_.Name):`t$($_.Value)" }) -join [Environment]::NewLine + } + } + + $AzMcInfo += [PSCustomObject]$InObj + } + + if ($InfoLevel.MaintenanceConfiguration -ge 2) { + Paragraph ($LocalizedData.ParagraphDetail -f $AzSubscription.Name) + foreach ($AzMcItem in $AzMcInfo) { + $McName = $AzMcItem.($LocalizedData.Name) + Section -Style NOTOCHeading5 -ExcludeFromTOC $McName { + $TableParams = @{ + Name = "$($LocalizedData.TableHeading) - $McName" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AzMcItem | Table @TableParams + } + } + } else { + Paragraph ($LocalizedData.ParagraphSummary -f $AzSubscription.Name) + BlankLine + $TableParams = @{ + Name = "$($LocalizedData.TableHeading) - $($AzSubscription.Name)" + List = $false + Columns = $LocalizedData.Name, $LocalizedData.Location, $LocalizedData.Scope, $LocalizedData.RecurEvery, $LocalizedData.Duration + ColumnWidths = 30, 15, 25, 15, 15 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AzMcInfo | Table @TableParams + } + } + } + } + } catch { + Write-PScriboMessage -IsWarning "$($LocalizedData.ErrorMessage) $($_.Exception.Message)" + } + } + + end {} +} diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzManagementGroup.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzManagementGroup.ps1 new file mode 100644 index 0000000..c3031d8 --- /dev/null +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzManagementGroup.ps1 @@ -0,0 +1,82 @@ +function Get-AbrAzManagementGroup { + <# + .SYNOPSIS + Used by As Built Report to retrieve Azure Management Group information + .DESCRIPTION + Documents the configuration of Azure Management Groups including the management group + hierarchy, parent relationships, child group counts, and subscription counts. + .NOTES + Version: 0.1.0 + Author: Tim Carman + Twitter: @tpcarman + Github: tpcarman + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param () + begin { + $LocalizedData = $reportTranslate.GetAbrAzManagementGroup + Write-PScriboMessage ($LocalizedData.InfoLevel -f $InfoLevel.ManagementGroup) + } + process { + if ($InfoLevel.ManagementGroup -ge 1) { + try { + $AzRootMG = Get-AzManagementGroup -GroupName $TenantId -Expand -Recurse -ErrorAction Stop + if ($AzRootMG) { + Write-PScriboMessage $LocalizedData.Collecting + Section -Style Heading2 $LocalizedData.Heading { + if ($Options.ShowSectionInfo) { + Paragraph $LocalizedData.SectionInfo + BlankLine + } + if ($Options.EnableDiagrams) { + try { + Get-AbrDiagAzManagementGroup -RootManagementGroup $AzRootMG + } catch { + Write-PScriboMessage -IsWarning ($LocalizedData.DiagramError -f $_.Exception.Message) + } + } + $OutObj = @() + $MgQueue = [System.Collections.Queue]::new() + $MgQueue.Enqueue(@{ MG = $AzRootMG; ParentName = $LocalizedData.None }) + while ($MgQueue.Count -gt 0) { + $MgQueueItem = $MgQueue.Dequeue() + $CurrentMG = $MgQueueItem.MG + $ParentName = $MgQueueItem.ParentName + $ChildGroupCount = ($CurrentMG.Children | Where-Object { $_.Type -like '*managementGroups*' } | Measure-Object).Count + $SubscriptionCount = ($CurrentMG.Children | Where-Object { $_.Type -like '*subscriptions*' } | Measure-Object).Count + $InObj = [Ordered]@{ + $LocalizedData.Name = $CurrentMG.DisplayName + $LocalizedData.Id = $CurrentMG.Name + $LocalizedData.ParentName = $ParentName + $LocalizedData.ChildGroupCount = $ChildGroupCount + $LocalizedData.SubscriptionCount = $SubscriptionCount + } + $OutObj += [PSCustomObject]$InObj + foreach ($MgChild in $CurrentMG.Children) { + if ($MgChild.Type -like '*managementGroups*') { + $MgQueue.Enqueue(@{ MG = $MgChild; ParentName = $CurrentMG.DisplayName }) + } + } + } + $TableParams = @{ + Name = $LocalizedData.TableHeading + List = $false + ColumnWidths = 25, 30, 25, 10, 10 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $OutObj | Table @TableParams + } + } + } catch { + Write-PScriboMessage -IsWarning "$($LocalizedData.ErrorMessage) $($_.Exception.Message)" + } + } + } + end {} +} diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzNetAppFiles.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzNetAppFiles.ps1 new file mode 100644 index 0000000..a53dbbd --- /dev/null +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzNetAppFiles.ps1 @@ -0,0 +1,633 @@ +function Get-AbrAzNetAppFiles { + <# + .SYNOPSIS + Used by As Built Report to retrieve Azure NetApp Files information + .DESCRIPTION + Documents the configuration of Azure NetApp Files including NetApp Accounts, + Capacity Pools, Volumes, Snapshots, Snapshot Policies, and Backup Policies. + .NOTES + Version: 0.1.0 + Author: Scott Eno + Github: cse-gh + .EXAMPLE + + .LINK + + #> + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '', Justification = 'The Azure service is named "Azure NetApp Files" (plural); Az.NetAppFiles uses the same plural prefix.')] + [CmdletBinding()] + param ( + ) + + begin { + $LocalizedData = $reportTranslate.GetAbrAzNetAppFiles + Write-PScriboMessage ($LocalizedData.InfoLevel -f $InfoLevel.NetAppFiles) + } + + process { + Try { + if ($InfoLevel.NetAppFiles -gt 0) { + $AzAnfAccounts = Get-AzNetAppFilesAccount | Sort-Object Name + if ($AzAnfAccounts) { + Write-PScriboMessage $LocalizedData.Collecting + Section -Style Heading4 $LocalizedData.Heading { + if ($Options.ShowSectionInfo) { + Paragraph $LocalizedData.SectionInfo + BlankLine + } + + # Cache pools and volumes per-account to avoid repeat API calls + $AccountMap = @{} + foreach ($NetAppAccount in $AzAnfAccounts) { + $AcctRg = $NetAppAccount.Id.Split('/')[4] + $AcctPools = @(Get-AzNetAppFilesPool -ResourceGroupName $AcctRg -AccountName $NetAppAccount.Name -ErrorAction SilentlyContinue | Sort-Object Name) + $AcctPoolVolMap = @{} + foreach ($CapacityPool in $AcctPools) { + $PoolShortName = $CapacityPool.Name.Split('/')[-1] + $AcctPoolVolMap[$PoolShortName] = @(Get-AzNetAppFilesVolume -ResourceGroupName $AcctRg -AccountName $NetAppAccount.Name -PoolName $PoolShortName -ErrorAction SilentlyContinue | Sort-Object Name) + } + $AccountMap[$NetAppAccount.Name] = @{ + Pools = $AcctPools + Volumes = $AcctPoolVolMap + ResourceGroup = $AcctRg + } + } + + #region NetApp Accounts + Section -Style Heading5 $LocalizedData.AccountsHeading { + Paragraph ($LocalizedData.AccountsSummary -f $AzSubscription.Name) + BlankLine + + $AzAccountInfo = @() + foreach ($NetAppAccount in $AzAnfAccounts) { + $KeySourceDisplay = if ($NetAppAccount.Encryption -and $NetAppAccount.Encryption.KeySource -eq 'Microsoft.KeyVault') { + $LocalizedData.CustomerManaged + } else { + $LocalizedData.PlatformManaged + } + $InObj = [Ordered]@{ + $LocalizedData.Name = $NetAppAccount.Name + $LocalizedData.ResourceGroup = $NetAppAccount.ResourceGroupName + $LocalizedData.Location = $AzLocationLookup."$($NetAppAccount.Location)" + $LocalizedData.ProvisioningState = $NetAppAccount.ProvisioningState + $LocalizedData.EncryptionKeySource = $KeySourceDisplay + } + + if ($Options.ShowTags) { + $InObj[$LocalizedData.Tags] = if ($null -eq $NetAppAccount.Tags -or $NetAppAccount.Tags.Count -eq 0) { + $LocalizedData.None + } else { + ($NetAppAccount.Tags.Keys | ForEach-Object { "$_`:`t$($NetAppAccount.Tags[$_])" }) -join [Environment]::NewLine + } + } + + $AzAccountInfo += [PSCustomObject]$InObj + } + + if ($Healthcheck.NetAppFiles.CustomerManagedKey) { + $AzAccountInfo | Where-Object { $_.$($LocalizedData.EncryptionKeySource) -eq $LocalizedData.PlatformManaged } | Set-Style -Style Info -Property $LocalizedData.EncryptionKeySource + } + + if ($InfoLevel.NetAppFiles -ge 2) { + # Per-account detail: AD + encryption + foreach ($NetAppAccount in $AzAnfAccounts) { + $AcctDetail = $AzAccountInfo | Where-Object { $_.$($LocalizedData.Name) -eq $NetAppAccount.Name } + Section -Style NOTOCHeading5 -ExcludeFromTOC "$($NetAppAccount.Name)" { + $TableParams = @{ + Name = "NetApp Account - $($NetAppAccount.Name)" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AcctDetail | Table @TableParams + + # Active Directory configurations + if ($NetAppAccount.ActiveDirectories -and $NetAppAccount.ActiveDirectories.Count -gt 0) { + Section -Style NOTOCHeading6 -ExcludeFromTOC $LocalizedData.ActiveDirectoryHeading { + $AdInfo = @() + foreach ($Ad in $NetAppAccount.ActiveDirectories) { + $AdObj = [Ordered]@{ + $LocalizedData.Domain = if ($Ad.Domain) { $Ad.Domain } else { '--' } + $LocalizedData.Username = if ($Ad.Username) { $Ad.Username } else { '--' } + $LocalizedData.Site = if ($Ad.Site) { $Ad.Site } else { '--' } + $LocalizedData.OrganizationalUnit = if ($Ad.OrganizationalUnit) { $Ad.OrganizationalUnit } else { '--' } + $LocalizedData.SmbServerName = if ($Ad.SmbServerName) { $Ad.SmbServerName } else { '--' } + $LocalizedData.DnsServers = if ($Ad.Dns) { $Ad.Dns } else { '--' } + $LocalizedData.AesEncryption = if ($Ad.AesEncryption) { $LocalizedData.Yes } else { $LocalizedData.No } + $LocalizedData.LdapSigning = if ($Ad.LdapSigning) { $LocalizedData.Yes } else { $LocalizedData.No } + $LocalizedData.EncryptDCConnection = if ($Ad.EncryptDCConnections) { $LocalizedData.Yes } else { $LocalizedData.No } + $LocalizedData.AllowLocalNfsUsersWithLdap = if ($Ad.AllowLocalNfsUsersWithLdap) { $LocalizedData.Yes } else { $LocalizedData.No } + $LocalizedData.Status = if ($Ad.Status) { $Ad.Status } else { '--' } + } + $AdInfo += [PSCustomObject]$AdObj + } + + if ($Healthcheck.NetAppFiles.AdHealth) { + $AdInfo | Where-Object { $_.$($LocalizedData.Status) -and $_.$($LocalizedData.Status) -ne $LocalizedData.InUse } | Set-Style -Style Warning -Property $LocalizedData.Status + } + + $TableParams = @{ + Name = "Active Directory - $($NetAppAccount.Name)" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AdInfo | Table @TableParams + } + } + + # Encryption detail if customer-managed + if ($NetAppAccount.Encryption -and $NetAppAccount.Encryption.KeySource -eq 'Microsoft.KeyVault') { + Section -Style NOTOCHeading6 -ExcludeFromTOC $LocalizedData.EncryptionHeading { + $EncObj = [Ordered]@{ + $LocalizedData.EncryptionKeySource = $LocalizedData.CustomerManaged + $LocalizedData.EncryptionKeyVault = if ($NetAppAccount.Encryption.KeyVaultProperties -and $NetAppAccount.Encryption.KeyVaultProperties.KeyVaultUri) { $NetAppAccount.Encryption.KeyVaultProperties.KeyVaultUri } else { '--' } + $LocalizedData.EncryptionKeyName = if ($NetAppAccount.Encryption.KeyVaultProperties -and $NetAppAccount.Encryption.KeyVaultProperties.KeyName) { $NetAppAccount.Encryption.KeyVaultProperties.KeyName } else { '--' } + } + $TableParams = @{ + Name = "Encryption - $($NetAppAccount.Name)" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + [PSCustomObject]$EncObj | Table @TableParams + } + } + } + } + } else { + $TableParams = @{ + Name = "NetApp Accounts - $($AzSubscription.Name)" + List = $false + Columns = $LocalizedData.Name, $LocalizedData.ResourceGroup, $LocalizedData.Location, $LocalizedData.ProvisioningState, $LocalizedData.EncryptionKeySource + ColumnWidths = 25, 20, 15, 15, 25 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AzAccountInfo | Table @TableParams + } + } + #endregion NetApp Accounts + + #region Capacity Pools + $AllPools = @() + foreach ($NetAppAccount in $AzAnfAccounts) { + $AllPools += $AccountMap[$NetAppAccount.Name].Pools + } + if ($AllPools) { + Section -Style Heading5 $LocalizedData.PoolsHeading { + Paragraph ($LocalizedData.PoolsSummary -f $AzSubscription.Name) + BlankLine + + $AzPoolInfo = @() + foreach ($NetAppAccount in $AzAnfAccounts) { + foreach ($CapacityPool in $AccountMap[$NetAppAccount.Name].Pools) { + $PoolShortName = $CapacityPool.Name.Split('/')[-1] + $PoolVols = $AccountMap[$NetAppAccount.Name].Volumes[$PoolShortName] + $AllocatedBytes = 0 + if ($PoolVols) { + $AllocatedBytes = ($PoolVols | Measure-Object -Property UsageThreshold -Sum).Sum + if ($null -eq $AllocatedBytes) { $AllocatedBytes = 0 } + } + $PoolSizeGiB = [math]::Round($CapacityPool.Size / 1GB, 0) + $AllocatedGiB = [math]::Round($AllocatedBytes / 1GB, 0) + $PercentAllocated = if ($CapacityPool.Size -gt 0) { [math]::Round(($AllocatedBytes / $CapacityPool.Size) * 100, 1) } else { 0 } + + $InObj = [Ordered]@{ + $LocalizedData.Name = $PoolShortName + $LocalizedData.Account = $NetAppAccount.Name + $LocalizedData.ResourceGroup = $CapacityPool.ResourceGroupName + $LocalizedData.Location = $AzLocationLookup."$($CapacityPool.Location)" + $LocalizedData.ServiceLevel = $CapacityPool.ServiceLevel + $LocalizedData.QosType = $CapacityPool.QosType + $LocalizedData.SizeTiB = [math]::Round($CapacityPool.Size / 1TB, 2) + $LocalizedData.VolumeCount = if ($PoolVols) { $PoolVols.Count } else { 0 } + $LocalizedData.AllocatedGiB = $AllocatedGiB + $LocalizedData.PercentAllocated = $PercentAllocated + $LocalizedData.TotalThroughput = if ($null -ne $CapacityPool.TotalThroughputMibps) { $CapacityPool.TotalThroughputMibps } else { '--' } + $LocalizedData.UtilizedThroughput = if ($null -ne $CapacityPool.UtilizedThroughputMibps) { $CapacityPool.UtilizedThroughputMibps } else { '--' } + $LocalizedData.CoolAccess = if ($CapacityPool.CoolAccess) { $LocalizedData.Yes } else { $LocalizedData.No } + $LocalizedData.EncryptionType = if ($CapacityPool.EncryptionType) { $CapacityPool.EncryptionType } else { '--' } + $LocalizedData.ProvisioningState = $CapacityPool.ProvisioningState + } + + if ($Options.ShowTags) { + $InObj[$LocalizedData.Tags] = if ($null -eq $CapacityPool.Tags -or $CapacityPool.Tags.Count -eq 0) { + $LocalizedData.None + } else { + ($CapacityPool.Tags.Keys | ForEach-Object { "$_`:`t$($CapacityPool.Tags[$_])" }) -join [Environment]::NewLine + } + } + + $AzPoolInfo += [PSCustomObject]$InObj + + # Health check: pool near allocation limit + if ($Healthcheck.NetAppFiles.PoolCapacity -and $PercentAllocated -ge 85) { + Paragraph ($LocalizedData.WarningPoolAllocation -f $PoolShortName, $PercentAllocated, $AllocatedGiB, $PoolSizeGiB) -Bold + } + } + } + + if ($Healthcheck.NetAppFiles.PoolCapacity) { + $AzPoolInfo | Where-Object { [double]$_.$($LocalizedData.PercentAllocated) -ge 85 } | Set-Style -Style Warning -Property $LocalizedData.PercentAllocated + } + + if ($InfoLevel.NetAppFiles -ge 2) { + foreach ($NetAppAccount in $AzAnfAccounts) { + foreach ($CapacityPool in $AccountMap[$NetAppAccount.Name].Pools) { + $PoolShortName = $CapacityPool.Name.Split('/')[-1] + $PoolDetail = $AzPoolInfo | Where-Object { $_.$($LocalizedData.Name) -eq $PoolShortName -and $_.$($LocalizedData.Account) -eq $NetAppAccount.Name } + Section -Style NOTOCHeading5 -ExcludeFromTOC "$($NetAppAccount.Name) / $PoolShortName" { + $TableParams = @{ + Name = "Capacity Pool - $PoolShortName" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $PoolDetail | Table @TableParams + } + } + } + } else { + $TableParams = @{ + Name = "Capacity Pools - $($AzSubscription.Name)" + List = $false + Columns = $LocalizedData.Name, $LocalizedData.Account, $LocalizedData.ServiceLevel, $LocalizedData.QosType, $LocalizedData.SizeTiB, $LocalizedData.VolumeCount, $LocalizedData.PercentAllocated + ColumnWidths = 18, 18, 12, 10, 12, 10, 20 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AzPoolInfo | Table @TableParams + } + } + } + #endregion Capacity Pools + + #region Volumes + $AllVolumes = @() + foreach ($NetAppAccount in $AzAnfAccounts) { + foreach ($PoolShortName in $AccountMap[$NetAppAccount.Name].Volumes.Keys) { + $AllVolumes += $AccountMap[$NetAppAccount.Name].Volumes[$PoolShortName] + } + } + if ($AllVolumes) { + Section -Style Heading5 $LocalizedData.VolumesHeading { + Paragraph ($LocalizedData.VolumesSummary -f $AzSubscription.Name) + BlankLine + + $AzVolInfo = @() + foreach ($Volume in $AllVolumes) { + $VolShortName = $Volume.Name.Split('/')[-1] + $ParentAccount = $Volume.Name.Split('/')[0] + $ParentPool = $Volume.Name.Split('/')[1] + $SnapPolName = if ($Volume.DataProtection -and $Volume.DataProtection.Snapshot -and $Volume.DataProtection.Snapshot.SnapshotPolicyId) { + $Volume.DataProtection.Snapshot.SnapshotPolicyId.Split('/')[-1] + } else { + $LocalizedData.NoPolicy + } + $BackupPolName = if ($Volume.DataProtection -and $Volume.DataProtection.Backup -and $Volume.DataProtection.Backup.BackupPolicyId) { + $Volume.DataProtection.Backup.BackupPolicyId.Split('/')[-1] + } else { + $LocalizedData.NoPolicy + } + + $InObj = [Ordered]@{ + $LocalizedData.Name = $VolShortName + $LocalizedData.Account = $ParentAccount + $LocalizedData.Pool = $ParentPool + $LocalizedData.ServiceLevel = $Volume.ServiceLevel + $LocalizedData.QuotaGiB = [math]::Round($Volume.UsageThreshold / 1GB, 0) + $LocalizedData.Protocol = ($Volume.ProtocolTypes -join ', ') + $LocalizedData.SnapshotPolicy = $SnapPolName + $LocalizedData.BackupPolicy = $BackupPolName + $LocalizedData.VolumeType = if ($Volume.VolumeType) { $Volume.VolumeType } else { 'Regular' } + $LocalizedData.ProvisioningState = $Volume.ProvisioningState + } + + if ($Options.ShowTags) { + $InObj[$LocalizedData.Tags] = if ($null -eq $Volume.Tags -or $Volume.Tags.Count -eq 0) { + $LocalizedData.None + } else { + ($Volume.Tags.Keys | ForEach-Object { "$_`:`t$($Volume.Tags[$_])" }) -join [Environment]::NewLine + } + } + + $AzVolInfo += [PSCustomObject]$InObj + } + + if ($Healthcheck.NetAppFiles.SnapshotPolicy) { + $AzVolInfo | Where-Object { $_.$($LocalizedData.SnapshotPolicy) -eq $LocalizedData.NoPolicy } | Set-Style -Style Info -Property $LocalizedData.SnapshotPolicy + } + if ($Healthcheck.NetAppFiles.BackupProtection) { + $AzVolInfo | Where-Object { $_.$($LocalizedData.BackupPolicy) -eq $LocalizedData.NoPolicy } | Set-Style -Style Info -Property $LocalizedData.BackupPolicy + } + + if ($InfoLevel.NetAppFiles -ge 3) { + # Per-volume vertical detail sections + foreach ($Volume in $AllVolumes) { + $VolShortName = $Volume.Name.Split('/')[-1] + $ParentAccount = $Volume.Name.Split('/')[0] + $ParentPool = $Volume.Name.Split('/')[1] + Section -Style NOTOCHeading5 -ExcludeFromTOC "$ParentAccount / $ParentPool / $VolShortName" { + $SnapPolName = if ($Volume.DataProtection -and $Volume.DataProtection.Snapshot -and $Volume.DataProtection.Snapshot.SnapshotPolicyId) { + $Volume.DataProtection.Snapshot.SnapshotPolicyId.Split('/')[-1] + } else { + $LocalizedData.NoPolicy + } + $BackupPolName = if ($Volume.DataProtection -and $Volume.DataProtection.Backup -and $Volume.DataProtection.Backup.BackupPolicyId) { + $Volume.DataProtection.Backup.BackupPolicyId.Split('/')[-1] + } else { + $LocalizedData.NoPolicy + } + $SubnetShort = if ($Volume.SubnetId) { $Volume.SubnetId.Split('/')[-1] } else { '--' } + $ZoneDisplay = if ($Volume.Zones -and $Volume.Zones.Count -gt 0) { $Volume.Zones -join ', ' } elseif ($Volume.ProvisionedAvailabilityZone) { $Volume.ProvisionedAvailabilityZone } else { '--' } + + $VolDetail = [Ordered]@{ + $LocalizedData.Name = $VolShortName + $LocalizedData.Account = $ParentAccount + $LocalizedData.Pool = $ParentPool + $LocalizedData.Location = $AzLocationLookup."$($Volume.Location)" + $LocalizedData.ServiceLevel = $Volume.ServiceLevel + $LocalizedData.VolumeType = if ($Volume.VolumeType) { $Volume.VolumeType } else { 'Regular' } + $LocalizedData.Protocol = ($Volume.ProtocolTypes -join ', ') + $LocalizedData.QuotaGiB = [math]::Round($Volume.UsageThreshold / 1GB, 0) + $LocalizedData.Throughput = if ($null -ne $Volume.ThroughputMibps) { $Volume.ThroughputMibps } else { '--' } + $LocalizedData.ActualThroughput = if ($null -ne $Volume.ActualThroughputMibps) { $Volume.ActualThroughputMibps } else { '--' } + $LocalizedData.Subnet = $SubnetShort + $LocalizedData.NetworkFeatures = if ($Volume.NetworkFeatures) { $Volume.NetworkFeatures } else { '--' } + $LocalizedData.Zone = $ZoneDisplay + $LocalizedData.SecurityStyle = if ($Volume.SecurityStyle) { $Volume.SecurityStyle } else { '--' } + $LocalizedData.UnixPermission = if ($Volume.UnixPermission) { $Volume.UnixPermission } else { '--' } + $LocalizedData.SnapshotPolicy = $SnapPolName + $LocalizedData.BackupPolicy = $BackupPolName + $LocalizedData.SnapshotDirVisible = if ($Volume.SnapshotDirectoryVisible) { $LocalizedData.Yes } else { $LocalizedData.No } + $LocalizedData.KerberosEnabled = if ($Volume.KerberosEnabled) { $LocalizedData.Yes } else { $LocalizedData.No } + $LocalizedData.LdapEnabled = if ($Volume.LdapEnabled) { $LocalizedData.Yes } else { $LocalizedData.No } + $LocalizedData.SmbEncryption = if ($Volume.SmbEncryption) { $LocalizedData.Yes } else { $LocalizedData.No } + $LocalizedData.SmbContinuouslyAvailable = if ($Volume.SmbContinuouslyAvailable) { $LocalizedData.Yes } else { $LocalizedData.No } + $LocalizedData.SmbAccessBasedEnumeration = if ($Volume.SmbAccessBasedEnumeration) { $Volume.SmbAccessBasedEnumeration } else { '--' } + $LocalizedData.CoolAccess = if ($Volume.CoolAccess) { $LocalizedData.Yes } else { $LocalizedData.No } + $LocalizedData.CoolnessPeriod = if ($Volume.CoolAccess -and $null -ne $Volume.CoolnessPeriod) { $Volume.CoolnessPeriod } else { '--' } + $LocalizedData.TieringPolicy = if ($Volume.CoolAccess -and $Volume.CoolAccessTieringPolicy) { $Volume.CoolAccessTieringPolicy } else { '--' } + $LocalizedData.RetrievalPolicy = if ($Volume.CoolAccess -and $Volume.CoolAccessRetrievalPolicy) { $Volume.CoolAccessRetrievalPolicy } else { '--' } + $LocalizedData.FileSystemId = if ($Volume.FileSystemId) { $Volume.FileSystemId } else { '--' } + $LocalizedData.ProvisioningState = $Volume.ProvisioningState + } + $VolObj = [PSCustomObject]$VolDetail + if ($Healthcheck.NetAppFiles.SnapshotPolicy) { + $VolObj | Where-Object { $_.$($LocalizedData.SnapshotPolicy) -eq $LocalizedData.NoPolicy } | Set-Style -Style Info -Property $LocalizedData.SnapshotPolicy + } + if ($Healthcheck.NetAppFiles.BackupProtection) { + $VolObj | Where-Object { $_.$($LocalizedData.BackupPolicy) -eq $LocalizedData.NoPolicy } | Set-Style -Style Info -Property $LocalizedData.BackupPolicy + } + $TableParams = @{ + Name = "Volume - $VolShortName" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $VolObj | Table @TableParams + + # Mount Targets + if ($Volume.MountTargets -and $Volume.MountTargets.Count -gt 0) { + Section -Style NOTOCHeading6 -ExcludeFromTOC $LocalizedData.MountTargetsHeading { + $MtInfo = @() + foreach ($MountTarget in $Volume.MountTargets) { + $MtInfo += [PSCustomObject][Ordered]@{ + $LocalizedData.IpAddress = if ($MountTarget.IPAddress) { $MountTarget.IPAddress } else { '--' } + $LocalizedData.SmbServerFqdn = if ($MountTarget.SmbServerFqdn) { $MountTarget.SmbServerFqdn } else { '--' } + $LocalizedData.FileSystemId = if ($MountTarget.FileSystemId) { $MountTarget.FileSystemId } else { '--' } + } + } + $TableParams = @{ + Name = "Mount Targets - $VolShortName" + List = $false + ColumnWidths = 25, 40, 35 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $MtInfo | Table @TableParams + } + } + + # Export Policy Rules + if ($Volume.ExportPolicy -and $Volume.ExportPolicy.Rules -and $Volume.ExportPolicy.Rules.Count -gt 0) { + Section -Style NOTOCHeading6 -ExcludeFromTOC $LocalizedData.ExportPolicyHeading { + $EpInfo = @() + foreach ($Rule in ($Volume.ExportPolicy.Rules | Sort-Object RuleIndex)) { + $EpInfo += [PSCustomObject][Ordered]@{ + $LocalizedData.RuleIndex = $Rule.RuleIndex + $LocalizedData.AllowedClients = if ($Rule.AllowedClients) { $Rule.AllowedClients } else { '--' } + $LocalizedData.Nfsv3 = if ($Rule.Nfsv3) { $LocalizedData.Yes } else { $LocalizedData.No } + $LocalizedData.Nfsv41 = if ($Rule.Nfsv41) { $LocalizedData.Yes } else { $LocalizedData.No } + $LocalizedData.UnixReadWrite = if ($Rule.UnixReadWrite) { $LocalizedData.Yes } else { $LocalizedData.No } + $LocalizedData.UnixReadOnly = if ($Rule.UnixReadOnly) { $LocalizedData.Yes } else { $LocalizedData.No } + $LocalizedData.HasRootAccess = if ($Rule.HasRootAccess) { $LocalizedData.Yes } else { $LocalizedData.No } + $LocalizedData.ChownMode = if ($Rule.ChownMode) { $Rule.ChownMode } else { '--' } + } + } + $TableParams = @{ + Name = "Export Policy - $VolShortName" + List = $false + ColumnWidths = 8, 30, 10, 10, 12, 12, 10, 8 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $EpInfo | Table @TableParams + } + } + + # Snapshots and Quota Rules (InfoLevel 4) + if ($InfoLevel.NetAppFiles -ge 4) { + $VolRg = $Volume.Id.Split('/')[4] + $Snapshots = Get-AzNetAppFilesSnapshot -ResourceGroupName $VolRg -AccountName $ParentAccount -PoolName $ParentPool -VolumeName $VolShortName -ErrorAction SilentlyContinue | Sort-Object Created -Descending + if ($Snapshots) { + Section -Style NOTOCHeading6 -ExcludeFromTOC $LocalizedData.SnapshotsHeading { + $SnapInfo = @() + foreach ($Snapshot in $Snapshots) { + $SnapInfo += [PSCustomObject][Ordered]@{ + $LocalizedData.Name = $Snapshot.Name.Split('/')[-1] + $LocalizedData.Created = if ($Snapshot.Created) { ([datetime]$Snapshot.Created).ToString('yyyy-MM-dd HH:mm') } else { '--' } + $LocalizedData.ProvisioningState = if ($Snapshot.ProvisioningState) { $Snapshot.ProvisioningState } else { '--' } + } + } + $TableParams = @{ + Name = "Snapshots - $VolShortName" + List = $false + ColumnWidths = 50, 30, 20 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $SnapInfo | Table @TableParams + } + } + + $QuotaRules = Get-AzNetAppFilesVolumeQuotaRule -ResourceGroupName $VolRg -AccountName $ParentAccount -PoolName $ParentPool -VolumeName $VolShortName -ErrorAction SilentlyContinue + if ($QuotaRules) { + Section -Style NOTOCHeading6 -ExcludeFromTOC $LocalizedData.QuotaRulesHeading { + $QrInfo = @() + foreach ($QuotaRule in $QuotaRules) { + $QrInfo += [PSCustomObject][Ordered]@{ + $LocalizedData.Name = $QuotaRule.Name.Split('/')[-1] + $LocalizedData.Type = $QuotaRule.QuotaType + $LocalizedData.AllowedClients = if ($QuotaRule.QuotaTarget) { $QuotaRule.QuotaTarget } else { '--' } + $LocalizedData.QuotaGiB = if ($QuotaRule.QuotaSizeInKiBs) { [math]::Round($QuotaRule.QuotaSizeInKiBs / (1024 * 1024), 2) } else { 0 } + $LocalizedData.ProvisioningState = if ($QuotaRule.ProvisioningState) { $QuotaRule.ProvisioningState } else { '--' } + } + } + $TableParams = @{ + Name = "Quota Rules - $VolShortName" + List = $false + ColumnWidths = 25, 15, 30, 15, 15 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $QrInfo | Table @TableParams + } + } + } + } + } + } else { + $TableParams = @{ + Name = "Volumes - $($AzSubscription.Name)" + List = $false + Columns = $LocalizedData.Name, $LocalizedData.Account, $LocalizedData.Pool, $LocalizedData.Protocol, $LocalizedData.QuotaGiB, $LocalizedData.SnapshotPolicy, $LocalizedData.BackupPolicy + ColumnWidths = 20, 14, 14, 10, 10, 16, 16 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AzVolInfo | Table @TableParams + } + } + } + #endregion Volumes + + #region Snapshot Policies (InfoLevel >= 3) + if ($InfoLevel.NetAppFiles -ge 3) { + $AllSnapPolicies = @() + foreach ($NetAppAccount in $AzAnfAccounts) { + $AcctRg = $AccountMap[$NetAppAccount.Name].ResourceGroup + $Policies = Get-AzNetAppFilesSnapshotPolicy -ResourceGroupName $AcctRg -AccountName $NetAppAccount.Name -ErrorAction SilentlyContinue + if ($Policies) { + foreach ($Policy in $Policies) { + $AllSnapPolicies += [PSCustomObject]@{ + Account = $NetAppAccount.Name + Policy = $Policy + } + } + } + } + if ($AllSnapPolicies) { + Section -Style Heading5 $LocalizedData.SnapshotPoliciesHeading { + Paragraph ($LocalizedData.SnapshotPoliciesSummary -f $AzSubscription.Name) + BlankLine + + foreach ($Item in $AllSnapPolicies) { + $Policy = $Item.Policy + $PolShortName = $Policy.Name.Split('/')[-1] + $Hourly = if ($Policy.HourlySchedule -and $Policy.HourlySchedule.SnapshotsToKeep) { "Every hour at :$('{0:D2}' -f [int]$Policy.HourlySchedule.Minute), keep $($Policy.HourlySchedule.SnapshotsToKeep)" } else { $LocalizedData.NotConfigured } + $Daily = if ($Policy.DailySchedule -and $Policy.DailySchedule.SnapshotsToKeep) { "At $('{0:D2}' -f [int]$Policy.DailySchedule.Hour):$('{0:D2}' -f [int]$Policy.DailySchedule.Minute), keep $($Policy.DailySchedule.SnapshotsToKeep)" } else { $LocalizedData.NotConfigured } + $Weekly = if ($Policy.WeeklySchedule -and $Policy.WeeklySchedule.SnapshotsToKeep) { "$($Policy.WeeklySchedule.Day) at $('{0:D2}' -f [int]$Policy.WeeklySchedule.Hour):$('{0:D2}' -f [int]$Policy.WeeklySchedule.Minute), keep $($Policy.WeeklySchedule.SnapshotsToKeep)" } else { $LocalizedData.NotConfigured } + $Monthly = if ($Policy.MonthlySchedule -and $Policy.MonthlySchedule.SnapshotsToKeep) { "Day(s) $($Policy.MonthlySchedule.DaysOfMonth) at $('{0:D2}' -f [int]$Policy.MonthlySchedule.Hour):$('{0:D2}' -f [int]$Policy.MonthlySchedule.Minute), keep $($Policy.MonthlySchedule.SnapshotsToKeep)" } else { $LocalizedData.NotConfigured } + + Section -Style NOTOCHeading5 -ExcludeFromTOC "$($Item.Account) / $PolShortName" { + $SpObj = [PSCustomObject][Ordered]@{ + $LocalizedData.Name = $PolShortName + $LocalizedData.Account = $Item.Account + $LocalizedData.Enabled = if ($Policy.Enabled) { $LocalizedData.Yes } else { $LocalizedData.No } + $LocalizedData.HourlySchedule = $Hourly + $LocalizedData.DailySchedule = $Daily + $LocalizedData.WeeklySchedule = $Weekly + $LocalizedData.MonthlySchedule = $Monthly + } + $TableParams = @{ + Name = "Snapshot Policy - $PolShortName" + List = $true + ColumnWidths = 30, 70 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $SpObj | Table @TableParams + } + } + } + } + } + #endregion Snapshot Policies + + #region Backup Policies (InfoLevel >= 3) + if ($InfoLevel.NetAppFiles -ge 3) { + $AllBackupPolicies = @() + foreach ($NetAppAccount in $AzAnfAccounts) { + $AcctRg = $AccountMap[$NetAppAccount.Name].ResourceGroup + $Policies = Get-AzNetAppFilesBackupPolicy -ResourceGroupName $AcctRg -AccountName $NetAppAccount.Name -ErrorAction SilentlyContinue + if ($Policies) { + foreach ($Policy in $Policies) { + $AllBackupPolicies += [PSCustomObject]@{ + Account = $NetAppAccount.Name + Policy = $Policy + } + } + } + } + if ($AllBackupPolicies) { + Section -Style Heading5 $LocalizedData.BackupPoliciesHeading { + Paragraph ($LocalizedData.BackupPoliciesSummary -f $AzSubscription.Name) + BlankLine + + $BpInfo = @() + foreach ($Item in $AllBackupPolicies) { + $Policy = $Item.Policy + $PolShortName = $Policy.Name.Split('/')[-1] + $BpInfo += [PSCustomObject][Ordered]@{ + $LocalizedData.Name = $PolShortName + $LocalizedData.Account = $Item.Account + $LocalizedData.Enabled = if ($Policy.Enabled) { $LocalizedData.Yes } else { $LocalizedData.No } + $LocalizedData.DailyBackups = if ($null -ne $Policy.DailyBackupsToKeep) { $Policy.DailyBackupsToKeep } else { 0 } + $LocalizedData.WeeklyBackups = if ($null -ne $Policy.WeeklyBackupsToKeep) { $Policy.WeeklyBackupsToKeep } else { 0 } + $LocalizedData.MonthlyBackups = if ($null -ne $Policy.MonthlyBackupsToKeep) { $Policy.MonthlyBackupsToKeep } else { 0 } + } + } + $TableParams = @{ + Name = "Backup Policies - $($AzSubscription.Name)" + List = $false + Columns = $LocalizedData.Name, $LocalizedData.Account, $LocalizedData.Enabled, $LocalizedData.DailyBackups, $LocalizedData.WeeklyBackups, $LocalizedData.MonthlyBackups + ColumnWidths = 25, 20, 10, 15, 15, 15 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $BpInfo | Table @TableParams + } + } + } + #endregion Backup Policies + } + } + } + } Catch { + Write-PScriboMessage -IsWarning $($_.Exception.Message) + } + } + + end {} +} diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzNetworkSecurityGroup.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzNetworkSecurityGroup.ps1 similarity index 100% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzNetworkSecurityGroup.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzNetworkSecurityGroup.ps1 diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzNetworkSecurityGroupRule.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzNetworkSecurityGroupRule.ps1 similarity index 100% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzNetworkSecurityGroupRule.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzNetworkSecurityGroupRule.ps1 diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzNetworkVirtualAppliance.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzNetworkVirtualAppliance.ps1 new file mode 100644 index 0000000..50049e5 --- /dev/null +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzNetworkVirtualAppliance.ps1 @@ -0,0 +1,320 @@ +function Get-AbrAzNetworkVirtualAppliance { + <# + .SYNOPSIS + Used by As Built Report to retrieve Azure Network Virtual Appliance information. + .DESCRIPTION + Identifies third-party Network Virtual Appliances (NVAs) deployed in an Azure subscription + by inspecting VM marketplace image publisher metadata and optional resource tags. Renders + a summary table at InfoLevel 1, per-NVA detail lists at InfoLevel 2, and associated UDR + route table cross-reference at InfoLevel 3. + .NOTES + Version: 0.1.0 + Author: Tim Carman + Twitter: @tpcarman + Github: tpcarman + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param () + + begin { + $LocalizedData = $reportTranslate.GetAbrAzNetworkVirtualAppliance + Write-PScriboMessage ($LocalizedData.InfoLevel -f $InfoLevel.NetworkVirtualAppliance) + } + + process { + Try { + if ($InfoLevel.NetworkVirtualAppliance -gt 0) { + + #region --- NVA publisher list --- + # Default well-known NVA publishers. Overridden by Options.NvaPublishers when set. + $DefaultNvaPublishers = @( + 'paloaltonetworks', + 'fortinet', + 'cisco', + 'checkpoint', + 'f5-networks', + 'barracudanetworks', + 'sonicwall-inc', + 'juniper-networks', + 'viptela', + 'riverbed' + ) + + $NvaPublishers = if ($Options.NvaPublishers -and $Options.NvaPublishers.Count -gt 0) { + $Options.NvaPublishers + } else { + $DefaultNvaPublishers + } + + $NvaTagKey = if ($Options.NvaTag) { ($Options.NvaTag -split '=')[0].Trim() } else { $null } + $NvaTagValue = if ($Options.NvaTag -and $Options.NvaTag -contains '=') { ($Options.NvaTag -split '=',2)[1].Trim() } else { $null } + #endregion + + Write-PScriboMessage $LocalizedData.Collecting + + #region --- Pre-collect route tables and load balancers for UDR cross-reference (InfoLevel 3) --- + $AllRouteTables = @() + $AllLoadBalancers = @() + if ($InfoLevel.NetworkVirtualAppliance -ge 3) { + $AllRouteTables = Get-AzRouteTable -ErrorAction SilentlyContinue + # NVA HA pairs are commonly deployed behind an Internal Load Balancer, with UDRs + # pointing at the ILB's frontend IP rather than any individual appliance NIC. + $AllLoadBalancers = Get-AzLoadBalancer -ErrorAction SilentlyContinue + } + #endregion + + #region --- Collect all VMs and filter to NVAs --- + $AzVms = Get-AzVM -Status | Sort-Object Name + $NvaVms = @() + + foreach ($AzVm in $AzVms) { + $ImageRef = $AzVm.StorageProfile.ImageReference + $IsNvaByImg = $ImageRef.Publisher -and ($NvaPublishers -contains $ImageRef.Publisher.ToLower()) + + $IsNvaByTag = $false + if ($NvaTagKey) { + $TagVal = $AzVm.Tags[$NvaTagKey] + $IsNvaByTag = if ($NvaTagValue) { $TagVal -eq $NvaTagValue } else { $null -ne $TagVal } + } + + if (-not ($IsNvaByImg -or $IsNvaByTag)) { continue } + + Write-PScriboMessage ($LocalizedData.Processing -f $AzVm.Name) + + #region --- Resolve primary NIC --- + $PrimaryNicId = ($AzVm.NetworkProfile.NetworkInterfaces | Where-Object { $_.Primary } | Select-Object -First 1).Id + if (-not $PrimaryNicId) { + $PrimaryNicId = $AzVm.NetworkProfile.NetworkInterfaces[0].Id + } + $PrimaryNicName = $PrimaryNicId.Split('/')[-1] + $PrimaryNicRg = $PrimaryNicId.Split('/')[4] + $PrimaryNic = Get-AzNetworkInterface -Name $PrimaryNicName -ResourceGroupName $PrimaryNicRg -ErrorAction SilentlyContinue + + $PrivateIp = $PrimaryNic.IpConfigurations[0].PrivateIpAddress + $VNetSubnet = if ($PrimaryNic.IpConfigurations[0].Subnet.Id) { + $Parts = $PrimaryNic.IpConfigurations[0].Subnet.Id.Split('/') + "$($Parts[$Parts.IndexOf('virtualNetworks') + 1]) / $($Parts[-1])" + } else { '--' } + + $AllNicNames = ($AzVm.NetworkProfile.NetworkInterfaces | ForEach-Object { $_.Id.Split('/')[-1] }) -join ', ' + #endregion + + #region --- Vendor display name --- + $VendorDisplay = switch ($ImageRef.Publisher.ToLower()) { + 'paloaltonetworks' { 'Palo Alto Networks' } + 'fortinet' { 'Fortinet' } + 'cisco' { 'Cisco' } + 'checkpoint' { 'Check Point' } + 'f5-networks' { 'F5 Networks' } + 'barracudanetworks' { 'Barracuda Networks' } + 'sonicwall-inc' { 'SonicWall' } + 'juniper-networks' { 'Juniper Networks' } + 'viptela' { 'Cisco Viptela (SD-WAN)' } + 'riverbed' { 'Riverbed' } + default { $ImageRef.Publisher } + } + if (-not $ImageRef.Publisher) { $VendorDisplay = $LocalizedData.TagIdentified } + #endregion + + #region --- Associated UDR route tables (InfoLevel 3) --- + $AssociatedRouteTables = @() + if ($InfoLevel.NetworkVirtualAppliance -ge 3) { + # Match against every private IP owned by this NVA (all NICs, not just the primary), + # plus the frontend private IP of any Load Balancer whose backend pool includes one of + # those NICs, since HA NVA pairs are commonly fronted by an Internal Load Balancer and + # UDRs route to the ILB's frontend IP rather than to an individual appliance NIC. + $MatchIps = [System.Collections.Generic.HashSet[string]]::new() + foreach ($NicRef in $AzVm.NetworkProfile.NetworkInterfaces) { + $Nic = if ($NicRef.Id -eq $PrimaryNicId) { + $PrimaryNic + } else { + Get-AzNetworkInterface -Name $NicRef.Id.Split('/')[-1] -ResourceGroupName $NicRef.Id.Split('/')[4] -ErrorAction SilentlyContinue + } + foreach ($IpConfig in $Nic.IpConfigurations) { + if ($IpConfig.PrivateIpAddress) { [void]$MatchIps.Add($IpConfig.PrivateIpAddress) } + foreach ($Lb in $AllLoadBalancers) { + foreach ($Pool in $Lb.BackendAddressPools) { + $IsPoolMember = ($Pool.BackendIpConfigurations.Id -contains $IpConfig.Id) -or + ($Pool.LoadBalancerBackendAddresses.NetworkInterfaceIpConfiguration.Id -contains $IpConfig.Id) -or + ($Pool.LoadBalancerBackendAddresses.IpAddress -contains $IpConfig.PrivateIpAddress) + if ($IsPoolMember) { + foreach ($Frontend in $Lb.FrontendIpConfigurations) { + if ($Frontend.PrivateIpAddress) { [void]$MatchIps.Add($Frontend.PrivateIpAddress) } + } + } + } + } + } + } + + foreach ($Rt in $AllRouteTables) { + $MatchingRoutes = $Rt.Routes | Where-Object { + $_.NextHopType -eq 'VirtualAppliance' -and $MatchIps.Contains($_.NextHopIpAddress) + } + if ($MatchingRoutes) { + foreach ($Route in $MatchingRoutes) { + $AssociatedRouteTables += [PSCustomObject][Ordered]@{ + $LocalizedData.RouteTable = $Rt.Name + $LocalizedData.ResourceGroup = $Rt.ResourceGroupName + $LocalizedData.RouteName = $Route.Name + $LocalizedData.AddressPrefix = $Route.AddressPrefix + } + } + } + } + } + #endregion + + $NvaVms += [PSCustomObject]@{ + Name = $AzVm.Name + ResourceGroup = $AzVm.ResourceGroupName + Location = $AzLocationLookup."$($AzVm.Location)" + Subscription = "$($AzSubscriptionLookup.(($AzVm.Id).split('/')[2]))" + SubscriptionID = ($AzVm.Id).split('/')[2] + Vendor = $VendorDisplay + Publisher = if ($ImageRef.Publisher) { $ImageRef.Publisher } else { '--' } + Offer = if ($ImageRef.Offer) { $ImageRef.Offer } else { '--' } + Sku = if ($ImageRef.Sku) { $ImageRef.Sku } else { '--' } + ImageVersion = if ($ImageRef.ExactVersion) { $ImageRef.ExactVersion } elseif ($ImageRef.Version) { $ImageRef.Version } else { '--' } + Status = Switch ($AzVm.PowerState) { + 'Vm deallocated' { $LocalizedData.Deallocated } + 'Vm running' { $LocalizedData.Running } + default { $AzVm.PowerState } + } + Size = $AzVm.HardwareProfile.VmSize + PrivateIPAddress = if ($PrivateIp) { $PrivateIp } else { '--' } + VirtualNetworkSubnet = $VNetSubnet + NetworkInterfaces = $AllNicNames + Tags = if ($AzVm.Tags -and $AzVm.Tags.Count -gt 0) { + ($AzVm.Tags.GetEnumerator() | ForEach-Object { "$($_.Key) = $($_.Value)" }) -join [System.Environment]::NewLine + } else { $LocalizedData.None } + AssociatedRouteTables = $AssociatedRouteTables + DetectedBy = if ($IsNvaByImg -and $IsNvaByTag) { $LocalizedData.DetectedBoth } + elseif ($IsNvaByImg) { $LocalizedData.DetectedByPublisher } + else { $LocalizedData.DetectedByTag } + } + } + #endregion + + if ($NvaVms) { + Section -Style Heading4 $LocalizedData.Heading { + if ($Options.ShowSectionInfo) { + Paragraph $LocalizedData.SectionInfo + BlankLine + } + + if ($InfoLevel.NetworkVirtualAppliance -ge 2) { + #region --- InfoLevel 2+: per-NVA detail --- + Paragraph ($LocalizedData.ParagraphDetail -f $AzSubscription.Name) + BlankLine + + foreach ($Nva in $NvaVms) { + Section -Style NOTOCHeading5 -ExcludeFromTOC $Nva.Name { + $InObj = [Ordered]@{ + $LocalizedData.Name = $Nva.Name + $LocalizedData.ResourceGroup = $Nva.ResourceGroup + $LocalizedData.Location = $Nva.Location + $LocalizedData.Subscription = $Nva.Subscription + $LocalizedData.SubscriptionID = $Nva.SubscriptionID + $LocalizedData.Vendor = $Nva.Vendor + $LocalizedData.Publisher = $Nva.Publisher + $LocalizedData.Offer = $Nva.Offer + $LocalizedData.Sku = $Nva.Sku + $LocalizedData.ImageVersion = $Nva.ImageVersion + $LocalizedData.Status = $Nva.Status + $LocalizedData.Size = $Nva.Size + $LocalizedData.PrivateIPAddress = $Nva.PrivateIPAddress + $LocalizedData.VirtualNetworkSubnet = $Nva.VirtualNetworkSubnet + $LocalizedData.NetworkInterfaces = $Nva.NetworkInterfaces + $LocalizedData.DetectedBy = $Nva.DetectedBy + $LocalizedData.Tags = $Nva.Tags + } + $TableParams = @{ + Name = "$($LocalizedData.TableHeading) - $($Nva.Name)" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + [PSCustomObject]$InObj | Table @TableParams + + #region --- HealthCheck: NVA deallocated --- + if ($HealthCheck.NetworkVirtualAppliance.Status) { + if ($Nva.Status -eq $LocalizedData.Deallocated) { + [PSCustomObject]$InObj | Set-Style -Style Critical -Property $LocalizedData.Status + } + } + #endregion + + #region --- InfoLevel 3: associated UDR route tables --- + if ($InfoLevel.NetworkVirtualAppliance -ge 3) { + if ($Nva.AssociatedRouteTables -and $Nva.AssociatedRouteTables.Count -gt 0) { + Section -Style NOTOCHeading6 -ExcludeFromTOC $LocalizedData.AssociatedRoutes { + $RouteTableParams = @{ + Name = "$($LocalizedData.AssociatedRoutes) - $($Nva.Name)" + List = $false + ColumnWidths = 25, 25, 25, 25 + } + if ($Report.ShowTableCaptions) { + $RouteTableParams['Caption'] = "- $($RouteTableParams.Name)" + } + $Nva.AssociatedRouteTables | Table @RouteTableParams + } + } else { + Paragraph $LocalizedData.NoAssociatedRoutes + } + } + #endregion + } + } + #endregion + } else { + #region --- InfoLevel 1: summary table --- + Paragraph ($LocalizedData.ParagraphSummary -f $AzSubscription.Name) + BlankLine + + $NvaSummary = @() + foreach ($Nva in $NvaVms) { + $InObj = [Ordered]@{ + $LocalizedData.Name = $Nva.Name + $LocalizedData.ResourceGroup = $Nva.ResourceGroup + $LocalizedData.Location = $Nva.Location + $LocalizedData.Vendor = $Nva.Vendor + $LocalizedData.Offer = $Nva.Offer + $LocalizedData.Status = $Nva.Status + $LocalizedData.PrivateIPAddress = $Nva.PrivateIPAddress + } + $NvaSummary += [PSCustomObject]$InObj + } + + $TableParams = @{ + Name = "$($LocalizedData.TableHeadings) - $($AzSubscription.Name)" + List = $false + ColumnWidths = 20, 16, 14, 14, 14, 10, 12 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $NvaSummary | Table @TableParams + + if ($HealthCheck.NetworkVirtualAppliance.Status) { + $NvaSummary | Where-Object { $_.$($LocalizedData.Status) -eq $LocalizedData.Deallocated } | + Set-Style -Style Critical -Property $LocalizedData.Status + } + #endregion + } + } + } + } + } Catch { + Write-PScriboMessage -IsWarning $($_.Exception.Message) + } + } + + end {} +} \ No newline at end of file diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzNetworkWatcher.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzNetworkWatcher.ps1 new file mode 100644 index 0000000..9e28aee --- /dev/null +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzNetworkWatcher.ps1 @@ -0,0 +1,165 @@ +function Get-AbrAzNetworkWatcher { + <# + .SYNOPSIS + Used by As Built Report to retrieve Azure Network Watcher and Flow Log information + .DESCRIPTION + Documents the configuration of Azure Network Watchers and their associated NSG Flow Logs, + including retention policy, traffic analytics, and storage account settings. + .NOTES + Version: 0.1.0 + Author: Tim Carman + Twitter: @tpcarman + Github: tpcarman + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param () + + begin { + $LocalizedData = $reportTranslate.GetAbrAzNetworkWatcher + Write-PScriboMessage ($LocalizedData.InfoLevel -f $InfoLevel.NetworkWatcher) + } + + process { + try { + if ($InfoLevel.NetworkWatcher -ge 1) { + $AzNetworkWatchers = Get-AzNetworkWatcher -ErrorAction SilentlyContinue | Sort-Object Name + if ($AzNetworkWatchers) { + Write-PScriboMessage $LocalizedData.Collecting + + # Pre-collect flow logs per watcher for use at both InfoLevels + $FlowLogsMap = @{} + foreach ($AzWatcher in $AzNetworkWatchers) { + $FlowLogsMap[$AzWatcher.Name] = Get-AzNetworkWatcherFlowLog -NetworkWatcher $AzWatcher -ErrorAction SilentlyContinue + } + + Section -Style Heading4 $LocalizedData.Heading { + if ($Options.ShowSectionInfo) { + Paragraph $LocalizedData.SectionInfo + BlankLine + } + + $AzWatcherInfo = @() + foreach ($AzWatcher in $AzNetworkWatchers) { + $FlowLogCount = if ($FlowLogsMap[$AzWatcher.Name]) { @($FlowLogsMap[$AzWatcher.Name]).Count } else { 0 } + $InObj = [Ordered]@{ + $LocalizedData.Name = $AzWatcher.Name + $LocalizedData.ResourceGroup = $AzWatcher.ResourceGroupName + $LocalizedData.Location = $AzLocationLookup."$($AzWatcher.Location)" + $LocalizedData.Subscription = "$($AzSubscriptionLookup.(($AzWatcher.Id).split('/')[2]))" + $LocalizedData.SubscriptionID = ($AzWatcher.Id).split('/')[2] + $LocalizedData.FlowLogs = $FlowLogCount + $LocalizedData.ProvisioningState = $AzWatcher.ProvisioningState + } + + if ($Options.ShowTags) { + $InObj[$LocalizedData.Tags] = if ($null -eq $AzWatcher.Tag -or $AzWatcher.Tag.Count -eq 0) { + $LocalizedData.None + } else { + ($AzWatcher.Tag.GetEnumerator() | ForEach-Object { "$($_.Name):`t$($_.Value)" }) -join [Environment]::NewLine + } + } + + $AzWatcherInfo += [PSCustomObject]$InObj + } + + if ($Healthcheck.NetworkWatcher.ProvisioningState) { + $AzWatcherInfo | Where-Object { $_.$($LocalizedData.ProvisioningState) -ne 'Succeeded' } | Set-Style -Style Critical -Property $LocalizedData.ProvisioningState + } + + if ($InfoLevel.NetworkWatcher -ge 2) { + Paragraph ($LocalizedData.ParagraphDetail -f $AzSubscription.Name) + foreach ($AzWatcherItem in $AzWatcherInfo) { + $WatcherName = $AzWatcherItem.($LocalizedData.Name) + Section -Style NOTOCHeading5 -ExcludeFromTOC $WatcherName { + $TableParams = @{ + Name = "$($LocalizedData.TableHeading) - $WatcherName" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AzWatcherItem | Table @TableParams + + $FlowLogs = $FlowLogsMap[$WatcherName] + if ($FlowLogs) { + Section -Style NOTOCHeading6 -ExcludeFromTOC $LocalizedData.FlowLogsHeading { + $FlowLogInfo = @() + foreach ($FlowLog in $FlowLogs) { + $TargetResource = if ($FlowLog.TargetResourceId) { + ($FlowLog.TargetResourceId).split('/')[-1] + } else { + $LocalizedData.None + } + $StorageAccount = if ($FlowLog.StorageId) { + ($FlowLog.StorageId).split('/')[-1] + } else { + $LocalizedData.None + } + $RetentionDays = if ($FlowLog.RetentionPolicy.Enabled) { + $FlowLog.RetentionPolicy.Days + } else { + $LocalizedData.Unlimited + } + $TrafficAnalytics = if ($FlowLog.FlowAnalyticsConfiguration.NetworkWatcherFlowAnalyticsConfiguration.Enabled) { + $LocalizedData.Enabled + } else { + $LocalizedData.Disabled + } + $InObj = [Ordered]@{ + $LocalizedData.FlowLogName = $FlowLog.Name + $LocalizedData.TargetResource = $TargetResource + $LocalizedData.FlowLogEnabled = $FlowLog.Enabled + $LocalizedData.RetentionDays = $RetentionDays + $LocalizedData.TrafficAnalytics = $TrafficAnalytics + $LocalizedData.StorageAccount = $StorageAccount + $LocalizedData.ProvisioningState = $FlowLog.ProvisioningState + } + $FlowLogInfo += [PSCustomObject]$InObj + } + + if ($Healthcheck.NetworkWatcher.FlowLogEnabled) { + $FlowLogInfo | Where-Object { -not $_.$($LocalizedData.FlowLogEnabled) } | Set-Style -Style Warning -Property $LocalizedData.FlowLogEnabled + } + + $TableParams = @{ + Name = "$($LocalizedData.FlowLogsHeading) - $WatcherName" + List = $false + ColumnWidths = 20, 20, 10, 10, 15, 15, 10 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $FlowLogInfo | Table @TableParams + } + } + } + } + } else { + Paragraph ($LocalizedData.ParagraphSummary -f $AzSubscription.Name) + BlankLine + $TableParams = @{ + Name = "$($LocalizedData.TableHeading) - $($AzSubscription.Name)" + List = $false + Columns = $LocalizedData.Name, $LocalizedData.Location, $LocalizedData.FlowLogs, $LocalizedData.ProvisioningState + ColumnWidths = 30, 25, 20, 25 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AzWatcherInfo | Table @TableParams + } + } + } + } + } catch { + Write-PScriboMessage -IsWarning "$($LocalizedData.ErrorMessage) $($_.Exception.Message)" + } + } + + end {} +} diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzPolicy.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzPolicy.ps1 similarity index 100% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzPolicy.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzPolicy.ps1 diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzPolicyAssignment.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzPolicyAssignment.ps1 similarity index 100% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzPolicyAssignment.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzPolicyAssignment.ps1 diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzPolicyDefinition.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzPolicyDefinition.ps1 similarity index 100% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzPolicyDefinition.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzPolicyDefinition.ps1 diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzPrivateDnsZone.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzPrivateDnsZone.ps1 new file mode 100644 index 0000000..cfe8377 --- /dev/null +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzPrivateDnsZone.ps1 @@ -0,0 +1,160 @@ +function Get-AbrAzPrivateDnsZone { + <# + .SYNOPSIS + Used by As Built Report to retrieve Azure Private DNS Zone information + .DESCRIPTION + Documents the configuration of Azure Private DNS Zones including record set counts, + virtual network links, and provisioning state. + .NOTES + Version: 0.1.0 + Author: Tim Carman + Twitter: @tpcarman + Github: tpcarman + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param () + + begin { + $LocalizedData = $reportTranslate.GetAbrAzPrivateDnsZone + Write-PScriboMessage ($LocalizedData.InfoLevel -f $InfoLevel.PrivateDnsZone) + } + + process { + try { + if ($InfoLevel.PrivateDnsZone -ge 1) { + $AzPrivateDnsZones = Get-AzResource -ResourceType 'Microsoft.Network/privateDnsZones' -ExpandProperties -ErrorAction SilentlyContinue | Sort-Object Name + if ($AzPrivateDnsZones) { + Write-PScriboMessage $LocalizedData.Collecting + Section -Style Heading4 $LocalizedData.Heading { + if ($Options.ShowSectionInfo) { + Paragraph $LocalizedData.SectionInfo + BlankLine + } + + # Pre-collect VNet links per zone for InfoLevel 2 detail. + # Key is "ResourceGroup/ZoneName" to handle the same zone name in multiple resource groups. + $VNetLinksMap = @{} + if ($InfoLevel.PrivateDnsZone -ge 2) { + foreach ($AzPrivateDnsZone in $AzPrivateDnsZones) { + $VNetLinksMap["$($AzPrivateDnsZone.ResourceGroupName)/$($AzPrivateDnsZone.Name)"] = Get-AzPrivateDnsVirtualNetworkLink -ResourceGroupName $AzPrivateDnsZone.ResourceGroupName -ZoneName $AzPrivateDnsZone.Name -ErrorAction SilentlyContinue + } + } + + $LockMap = @{} + $AllLocks = Get-AzResourceLock -ErrorAction SilentlyContinue + foreach ($Lock in $AllLocks) { + $Key = $Lock.ResourceId.ToLower() + if (-not $LockMap.ContainsKey($Key)) { $LockMap[$Key] = @() } + $LockMap[$Key] += $Lock + } + + $AzPrivateDnsZoneInfo = @() + foreach ($AzPrivateDnsZone in $AzPrivateDnsZones) { + $InObj = [Ordered]@{ + $LocalizedData.Name = $AzPrivateDnsZone.Name + $LocalizedData.ResourceGroup = $AzPrivateDnsZone.ResourceGroupName + $LocalizedData.Location = if ($AzLocationLookup."$($AzPrivateDnsZone.Location)") { $AzLocationLookup."$($AzPrivateDnsZone.Location)" } else { $AzPrivateDnsZone.Location } + $LocalizedData.Subscription = "$($AzSubscriptionLookup.(($AzPrivateDnsZone.ResourceId).split('/')[2]))" + $LocalizedData.SubscriptionID = ($AzPrivateDnsZone.ResourceId).split('/')[2] + $LocalizedData.RecordSets = $AzPrivateDnsZone.Properties.NumberOfRecordSets + $LocalizedData.MaxRecordSets = $AzPrivateDnsZone.Properties.MaxNumberOfRecordSets + $LocalizedData.VirtualNetworkLinks = $AzPrivateDnsZone.Properties.NumberOfVirtualNetworkLinks + $LocalizedData.VNetLinksWithRegistration = $AzPrivateDnsZone.Properties.NumberOfVirtualNetworkLinksWithRegistration + $LocalizedData.ProvisioningState = $AzPrivateDnsZone.Properties.ProvisioningState + } + + $InObj[$LocalizedData.Locks] = $( + $rl = $LockMap[$AzPrivateDnsZone.ResourceId.ToLower()] + if ($rl) { ($rl | ForEach-Object { "$($_.Name) ($($_.Properties.Level))" }) -join [Environment]::NewLine } + else { $LocalizedData.None } + ) + + if ($Options.ShowTags) { + $InObj[$LocalizedData.Tags] = if ($null -eq $AzPrivateDnsZone.Tags -or $AzPrivateDnsZone.Tags.Count -eq 0) { + $LocalizedData.None + } else { + ($AzPrivateDnsZone.Tags.Keys | ForEach-Object { "$_`:`t$($AzPrivateDnsZone.Tags[$_])" }) -join [Environment]::NewLine + } + } + + $AzPrivateDnsZoneInfo += [PSCustomObject]$InObj + } + + if ($Healthcheck.PrivateDnsZone.ProvisioningState) { + $AzPrivateDnsZoneInfo | Where-Object { $_.$($LocalizedData.ProvisioningState) -ne 'Succeeded' } | Set-Style -Style Critical -Property $LocalizedData.ProvisioningState + } + if ($Healthcheck.PrivateDnsZone.VirtualNetworkLinks) { + $AzPrivateDnsZoneInfo | Where-Object { [int]$_.$($LocalizedData.VirtualNetworkLinks) -eq 0 } | Set-Style -Style Warning -Property $LocalizedData.VirtualNetworkLinks + } + + if ($InfoLevel.PrivateDnsZone -ge 2) { + Paragraph ($LocalizedData.ParagraphDetail -f $AzSubscription.Name) + foreach ($AzPrivateDnsZone in $AzPrivateDnsZoneInfo) { + Section -Style NOTOCHeading5 -ExcludeFromTOC "$($AzPrivateDnsZone.($LocalizedData.Name))" { + $TableParams = @{ + Name = "$($LocalizedData.TableHeading) - $($AzPrivateDnsZone.($LocalizedData.Name))" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AzPrivateDnsZone | Table @TableParams + + $AzZoneName = $AzPrivateDnsZone.($LocalizedData.Name) + $AzZoneRg = $AzPrivateDnsZone.($LocalizedData.ResourceGroup) + $VNetLinks = $VNetLinksMap["$AzZoneRg/$AzZoneName"] + if ($VNetLinks) { + Section -Style NOTOCHeading6 -ExcludeFromTOC $LocalizedData.VirtualNetworkLinks { + $VNetLinkInfo = @() + foreach ($VNetLink in $VNetLinks) { + $InObj = [Ordered]@{ + $LocalizedData.LinkName = $VNetLink.Name + $LocalizedData.VirtualNetwork = ($VNetLink.VirtualNetworkId).split('/')[-1] + $LocalizedData.AutoRegistration = $VNetLink.RegistrationEnabled + $LocalizedData.VirtualNetworkLinkState = $VNetLink.VirtualNetworkLinkState + $LocalizedData.ProvisioningState = $VNetLink.ProvisioningState + } + $VNetLinkInfo += [PSCustomObject]$InObj + } + $TableParams = @{ + Name = "$($LocalizedData.VirtualNetworkLinks) - $($AzZoneName)" + List = $false + ColumnWidths = 30, 25, 15, 15, 15 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $VNetLinkInfo | Table @TableParams + } + } + } + } + } else { + Paragraph ($LocalizedData.ParagraphSummary -f $AzSubscription.Name) + BlankLine + $TableParams = @{ + Name = "$($LocalizedData.TableHeading) - $($AzSubscription.Name)" + List = $false + Columns = $LocalizedData.Name, $LocalizedData.ResourceGroup, $LocalizedData.Location, $LocalizedData.RecordSets, $LocalizedData.VirtualNetworkLinks, $LocalizedData.ProvisioningState + ColumnWidths = 25, 20, 15, 15, 10, 15 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AzPrivateDnsZoneInfo | Table @TableParams + } + } + } + } + } catch { + Write-PScriboMessage -IsWarning "$($LocalizedData.ErrorMessage) $($_.Exception.Message)" + } + } + + end {} +} diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzPrivateEndpoint.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzPrivateEndpoint.ps1 similarity index 100% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzPrivateEndpoint.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzPrivateEndpoint.ps1 diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzPublicIpAddress.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzPublicIpAddress.ps1 new file mode 100644 index 0000000..c121c51 --- /dev/null +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzPublicIpAddress.ps1 @@ -0,0 +1,126 @@ +function Get-AbrAzPublicIpAddress { + <# + .SYNOPSIS + Used by As Built Report to retrieve Azure Public IP Address information + .DESCRIPTION + Documents the configuration of Azure Public IP Addresses including allocation method, + SKU, DNS settings, and associated resource. + .NOTES + Version: 0.1.0 + Author: Tim Carman + Twitter: @tpcarman + Github: tpcarman + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param () + + begin { + $LocalizedData = $reportTranslate.GetAbrAzPublicIpAddress + Write-PScriboMessage ($LocalizedData.InfoLevel -f $InfoLevel.PublicIpAddress) + } + + process { + try { + if ($InfoLevel.PublicIpAddress -ge 1) { + $AzPublicIps = Get-AzPublicIpAddress -ErrorAction SilentlyContinue | Sort-Object Name + if ($AzPublicIps) { + Write-PScriboMessage $LocalizedData.Collecting + Section -Style Heading4 $LocalizedData.Heading { + if ($Options.ShowSectionInfo) { + Paragraph $LocalizedData.SectionInfo + BlankLine + } + + $AzPublicIpInfo = @() + foreach ($AzPip in $AzPublicIps) { + $AssociatedResource = if ($AzPip.IpConfiguration.Id) { + ($AzPip.IpConfiguration.Id).split('/')[-3] + } else { + $LocalizedData.None + } + + $Zones = if ($AzPip.Zones -and $AzPip.Zones.Count -gt 0) { + $AzPip.Zones -join ', ' + } else { + $LocalizedData.None + } + + $InObj = [Ordered]@{ + $LocalizedData.Name = $AzPip.Name + $LocalizedData.ResourceGroup = $AzPip.ResourceGroupName + $LocalizedData.Location = $AzLocationLookup."$($AzPip.Location)" + $LocalizedData.Subscription = "$($AzSubscriptionLookup.(($AzPip.Id).split('/')[2]))" + $LocalizedData.SubscriptionID = ($AzPip.Id).split('/')[2] + $LocalizedData.SKU = $AzPip.Sku.Name + $LocalizedData.Tier = $AzPip.Sku.Tier + $LocalizedData.IpVersion = $AzPip.PublicIpAddressVersion + $LocalizedData.AllocationMethod = $AzPip.PublicIpAllocationMethod + $LocalizedData.IpAddress = if ($AzPip.IpAddress) { $AzPip.IpAddress } else { $LocalizedData.NotAssigned } + $LocalizedData.DnsLabel = if ($AzPip.DnsSettings.DomainNameLabel) { $AzPip.DnsSettings.DomainNameLabel } else { $LocalizedData.None } + $LocalizedData.Fqdn = if ($AzPip.DnsSettings.Fqdn) { $AzPip.DnsSettings.Fqdn } else { $LocalizedData.None } + $LocalizedData.Zones = $Zones + $LocalizedData.AssociatedResource = $AssociatedResource + $LocalizedData.ProvisioningState = $AzPip.ProvisioningState + } + + if ($Options.ShowTags) { + $InObj[$LocalizedData.Tags] = if ($null -eq $AzPip.Tag -or $AzPip.Tag.Count -eq 0) { + $LocalizedData.None + } else { + ($AzPip.Tag.GetEnumerator() | ForEach-Object { "$($_.Name):`t$($_.Value)" }) -join [Environment]::NewLine + } + } + + $AzPublicIpInfo += [PSCustomObject]$InObj + } + + if ($Healthcheck.PublicIpAddress.ProvisioningState) { + $AzPublicIpInfo | Where-Object { $_.$($LocalizedData.ProvisioningState) -ne 'Succeeded' } | Set-Style -Style Critical -Property $LocalizedData.ProvisioningState + } + if ($Healthcheck.PublicIpAddress.Unattached) { + $AzPublicIpInfo | Where-Object { $_.$($LocalizedData.AssociatedResource) -eq $LocalizedData.None } | Set-Style -Style Warning -Property $LocalizedData.AssociatedResource + } + + if ($InfoLevel.PublicIpAddress -ge 2) { + Paragraph ($LocalizedData.ParagraphDetail -f $AzSubscription.Name) + foreach ($AzPip in $AzPublicIpInfo) { + Section -Style NOTOCHeading5 -ExcludeFromTOC "$($AzPip.($LocalizedData.Name))" { + $TableParams = @{ + Name = "$($LocalizedData.TableHeading) - $($AzPip.($LocalizedData.Name))" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AzPip | Table @TableParams + } + } + } else { + Paragraph ($LocalizedData.ParagraphSummary -f $AzSubscription.Name) + BlankLine + $TableParams = @{ + Name = "$($LocalizedData.TableHeading) - $($AzSubscription.Name)" + List = $false + Columns = $LocalizedData.Name, $LocalizedData.ResourceGroup, $LocalizedData.Location, $LocalizedData.SKU, $LocalizedData.IpAddress, $LocalizedData.AllocationMethod, $LocalizedData.ProvisioningState + ColumnWidths = 20, 15, 15, 10, 15, 12, 13 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AzPublicIpInfo | Table @TableParams + } + } + } + } + } catch { + Write-PScriboMessage -IsWarning "$($LocalizedData.ErrorMessage) $($_.Exception.Message)" + } + } + + end {} +} diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzRecoveryServicesVault.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzRecoveryServicesVault.ps1 new file mode 100644 index 0000000..95c1f62 --- /dev/null +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzRecoveryServicesVault.ps1 @@ -0,0 +1,157 @@ +function Get-AbrAzRecoveryServicesVault { + <# + .SYNOPSIS + Used by As Built Report to retrieve Azure Recovery Services Vault information + .DESCRIPTION + + .NOTES + Version: 0.2.0 + Author: Tim Carman + Twitter: @tpcarman + Github: tpcarman + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param ( + ) + + begin { + $LocalizedData = $reportTranslate.GetAbrAzRecoveryServicesVault + Write-PScriboMessage ($LocalizedData.InfoLevel -f $InfoLevel.RecoveryServicesVault) + } + + process { + Try { + if ($InfoLevel.RecoveryServicesVault -gt 0) { + $AzRsvs = Get-AzRecoveryServicesVault | Sort-Object Name + if ($AzRsvs) { + Write-PscriboMessage $LocalizedData.Collecting + Section -Style Heading4 $LocalizedData.Heading { + if ($Options.ShowSectionInfo) { + Paragraph $LocalizedData.SectionInfo + BlankLine + } + $LockMap = @{} + $AllLocks = Get-AzResourceLock -ErrorAction SilentlyContinue + foreach ($Lock in $AllLocks) { + $Key = $Lock.ResourceId.ToLower() + if (-not $LockMap.ContainsKey($Key)) { $LockMap[$Key] = @() } + $LockMap[$Key] += $Lock + } + + $AzRsvInfo = @() + foreach ($AzRsv in $AzRsvs) { + $InObj = [Ordered]@{ + $LocalizedData.Name = $AzRsv.Name + $LocalizedData.ResourceGroup = $AzRsv.ResourceGroupName + $LocalizedData.Location = $AzLocationLookup."$($AzRsv.Location)" + $LocalizedData.Subscription = "$($AzSubscriptionLookup.(($AzRsv.Id).split('/')[2]))" + $LocalizedData.SubscriptionID = ($AzRsv.Id).split('/')[2] + $LocalizedData.ProvisioningState = $AzRsv.Properties.ProvisioningState + $LocalizedData.StorageRedundancy = Switch ($AzRsv.Properties.RedundancySettings.StandardTierStorageRedundancy) { + $null { $LocalizedData.None } + default { $AzRsv.Properties.RedundancySettings.StandardTierStorageRedundancy } + } + $LocalizedData.CrossRegionRestore = Switch ($AzRsv.Properties.RedundancySettings.CrossRegionRestore) { + $null { $LocalizedData.None } + default { $AzRsv.Properties.RedundancySettings.CrossRegionRestore } + } + $LocalizedData.SoftDeleteState = Switch ($AzRsv.Properties.SoftDeleteSettings.SoftDeleteState) { + $null { $LocalizedData.None } + default { $AzRsv.Properties.SoftDeleteSettings.SoftDeleteState } + } + $LocalizedData.SoftDeleteRetentionDays = Switch ($AzRsv.Properties.SoftDeleteSettings.SoftDeleteRetentionPeriodInDays) { + $null { $LocalizedData.None } + default { $AzRsv.Properties.SoftDeleteSettings.SoftDeleteRetentionPeriodInDays } + } + $LocalizedData.ImmutabilityState = Switch ($AzRsv.Properties.ImmutabilitySettings.ImmutabilityState) { + $null { $LocalizedData.None } + default { $AzRsv.Properties.ImmutabilitySettings.ImmutabilityState } + } + $LocalizedData.PublicNetworkAccess = Switch ($AzRsv.Properties.PublicNetworkAccess) { + $null { $LocalizedData.None } + default { $AzRsv.Properties.PublicNetworkAccess } + } + $LocalizedData.PrivateEndpointStateForBackup = Switch ($AzRsv.Properties.PrivateEndpointStateForBackup) { + $null { $LocalizedData.None } + default { $AzRsv.Properties.PrivateEndpointStateForBackup } + } + $LocalizedData.PrivateEndpointStateForSiteRecovery = Switch ($AzRsv.Properties.PrivateEndpointStateForSiteRecovery) { + $null { $LocalizedData.None } + default { $AzRsv.Properties.PrivateEndpointStateForSiteRecovery } + } + } + $InObj[$LocalizedData.Locks] = $( + $rl = $LockMap[$AzRsv.Id.ToLower()] + if ($rl) { ($rl | ForEach-Object { "$($_.Name) ($($_.Properties.Level))" }) -join [Environment]::NewLine } + else { $LocalizedData.None } + ) + $InObj[$LocalizedData.Tags] = $( + if ($AzRsv.Tags -and $AzRsv.Tags.Count -gt 0) { + ($AzRsv.Tags.GetEnumerator() | ForEach-Object { "$($_.Key): $($_.Value)" }) -join [Environment]::NewLine + } else { + $LocalizedData.None + } + ) + + $AzRsvInfo += [PSCustomObject]$InObj + } + + if ($Healthcheck.RecoveryServicesVault.ProvisioningState) { + $AzRsvInfo | Where-Object { $_.$($LocalizedData.ProvisioningState) -ne 'Succeeded' } | Set-Style -Style Critical -Property $LocalizedData.ProvisioningState + } + if ($Healthcheck.RecoveryServicesVault.PrivateEndpointStateForBackup) { + $AzRsvInfo | Where-Object { $_.$($LocalizedData.PrivateEndpointStateForBackup) -eq $LocalizedData.None } | Set-Style -Style Warning -Property $LocalizedData.PrivateEndpointStateForBackup + } + if ($Healthcheck.RecoveryServicesVault.SoftDeleteEnabled) { + $AzRsvInfo | Where-Object { $_.$($LocalizedData.SoftDeleteState) -eq 'Disabled' } | Set-Style -Style Warning -Property $LocalizedData.SoftDeleteState + } + if ($Healthcheck.RecoveryServicesVault.ImmutabilityEnabled) { + $AzRsvInfo | Where-Object { $_.$($LocalizedData.ImmutabilityState) -eq 'Disabled' } | Set-Style -Style Warning -Property $LocalizedData.ImmutabilityState + } + if ($Healthcheck.RecoveryServicesVault.PublicNetworkAccess) { + $AzRsvInfo | Where-Object { $_.$($LocalizedData.PublicNetworkAccess) -eq 'Enabled' } | Set-Style -Style Warning -Property $LocalizedData.PublicNetworkAccess + } + + if ($InfoLevel.RecoveryServicesVault -ge 2) { + Paragraph ($LocalizedData.ParagraphDetail -f $AzSubscription.Name) + foreach ($AzRsv in $AzRsvInfo) { + Section -Style NOTOCHeading5 -ExcludeFromTOC "$($AzRsv.($LocalizedData.Name))" { + $TableParams = @{ + Name = "$($LocalizedData.Heading) - $($AzRsv.($LocalizedData.Name))" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AzRsv | Table @TableParams + } + } + } else { + Paragraph ($LocalizedData.ParagraphSummary -f $AzSubscription.Name) + BlankLine + $TableParams = @{ + Name = "$($LocalizedData.TableHeadings) - $($AzSubscription.Name)" + List = $false + Columns = $LocalizedData.Name, $LocalizedData.ResourceGroup, $LocalizedData.Location + ColumnWidths = 33, 34, 33 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AzRsvinfo | Table @TableParams + } + } + } + } + } Catch { + Write-PScriboMessage -IsWarning $($_.Exception.Message) + } + } + + end {} +} diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzRouteTable.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzRouteTable.ps1 similarity index 91% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzRouteTable.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzRouteTable.ps1 index 672f480..5c02ed1 100644 --- a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzRouteTable.ps1 +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzRouteTable.ps1 @@ -35,6 +35,14 @@ function Get-AbrAzRouteTable { BlankLine } + $LockMap = @{} + $AllLocks = Get-AzResourceLock -ErrorAction SilentlyContinue + foreach ($Lock in $AllLocks) { + $Key = $Lock.ResourceId.ToLower() + if (-not $LockMap.ContainsKey($Key)) { $LockMap[$Key] = @() } + $LockMap[$Key] += $Lock + } + if ($InfoLevel.RouteTable -ge 3) { Paragraph ($LocalizedData.ParagraphDetail -f $AzSubscription.Name) BlankLine @@ -57,6 +65,12 @@ function Get-AbrAzRouteTable { ColumnWidths = 40, 60 } + $InObj[$LocalizedData.Locks] = $( + $rl = $LockMap[$AzRouteTable.Id.ToLower()] + if ($rl) { ($rl | ForEach-Object { "$($_.Name) ($($_.Properties.Level))" }) -join [Environment]::NewLine } + else { $LocalizedData.None } + ) + if ($Options.ShowTags) { $InObj[$LocalizedData.Tags] = if ([string]::IsNullOrEmpty($AzRouteTable.Tag)) { '--' diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzSABlobServiceProperty.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzSABlobServiceProperty.ps1 similarity index 100% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzSABlobServiceProperty.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzSABlobServiceProperty.ps1 diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzSAContainer.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzSAContainer.ps1 similarity index 84% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzSAContainer.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzSAContainer.ps1 index c869e15..454e96f 100644 --- a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzSAContainer.ps1 +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzSAContainer.ps1 @@ -36,7 +36,7 @@ function Get-AbrAzSAContainer { process { Try { - $AzSAContainers = Get-AzStorageAccount -ResourceGroupName $ResourceGroupName -StorageAccountName $StorageAccountName | Get-AzStorageContainer -ErrorAction SilentlyContinue | Sort-Object Name + $AzSAContainers = Get-AzRmStorageContainer -ResourceGroupName $ResourceGroupName -StorageAccountName $StorageAccountName -ErrorAction SilentlyContinue | Sort-Object Name if ($AzSAContainers) { Write-PscriboMessage $LocalizedData.Collecting Section -Style NOTOCHeading6 -ExcludeFromTOC $LocalizedData.Heading { @@ -47,14 +47,18 @@ function Get-AbrAzSAContainer { $Count ++ $InObj = [Ordered]@{ $LocalizedData.Name = $AzSAContainer.Name - $LocalizedData.LastModified = $AzSAContainer.LastModified.UtcDateTime.ToShortDateString() + $LocalizedData.LastModified = if ($AzSAContainer.LastModifiedTime) { + $AzSAContainer.LastModifiedTime.ToShortDateString() + } else { + $LocalizedData.None + } $LocalizedData.AnonymousAccessLevel = switch ($AzSAContainer.PublicAccess) { "None" { $LocalizedData.Private } "Blob" { $LocalizedData.Blob } "Container" { $LocalizedData.Container } default { $AzSAContainer.PublicAccess } } - $LocalizedData.LeaseState = $AzSAContainer.BlobContainerProperties.LeaseState + $LocalizedData.LeaseState = $AzSAContainer.LeaseState } $AzSAContInfo += [PSCustomObject]$InObj } diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzSAFileServiceProperty.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzSAFileServiceProperty.ps1 similarity index 100% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzSAFileServiceProperty.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzSAFileServiceProperty.ps1 diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzSAQueue.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzSAQueue.ps1 similarity index 88% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzSAQueue.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzSAQueue.ps1 index b1fd976..4199b34 100644 --- a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzSAQueue.ps1 +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzSAQueue.ps1 @@ -36,7 +36,8 @@ function Get-AbrAzSAQueue { process { Try { - $AzSAQueues = Get-AzStorageAccount -ResourceGroupName $ResourceGroupName -StorageAccountName $StorageAccountName | Get-AzStorageQueue -ErrorAction SilentlyContinue | Sort-Object Name + $AzStorageContext = New-AzStorageContext -StorageAccountName $StorageAccountName -UseConnectedAccount -ErrorAction SilentlyContinue + $AzSAQueues = Get-AzStorageQueue -Context $AzStorageContext -ErrorAction SilentlyContinue | Sort-Object Name if ($AzSAQueues) { Write-PscriboMessage $LocalizedData.Collecting Section -Style NOTOCHeading6 -ExcludeFromTOC $LocalizedData.Heading { diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzSAShare.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzSAShare.ps1 similarity index 76% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzSAShare.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzSAShare.ps1 index f8b2052..8a4c667 100644 --- a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzSAShare.ps1 +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzSAShare.ps1 @@ -36,7 +36,7 @@ function Get-AbrAzSAShare { process { Try { - $AzSAShares = Get-AzStorageAccount -ResourceGroupName $ResourceGroupName -StorageAccountName $StorageAccountName | Get-AzStorageShare -ErrorAction SilentlyContinue | Sort-Object Name + $AzSAShares = Get-AzRmStorageShare -ResourceGroupName $ResourceGroupName -StorageAccountName $StorageAccountName -ErrorAction SilentlyContinue | Where-Object { -not $_.SnapshotTime } | Sort-Object Name if ($AzSAShares) { Write-PscriboMessage $LocalizedData.Collecting Section -Style NOTOCHeading6 -ExcludeFromTOC $LocalizedData.Heading { @@ -47,18 +47,23 @@ function Get-AbrAzSAShare { $Count ++ $InObj = [Ordered]@{ $LocalizedData.Name = $AzSAShare.Name - $LocalizedData.ShareURL = $AzSAShare.CloudFileShare.Uri.AbsoluteUri - $LocalizedData.Quota = $(if ([string]::IsNullOrEmpty($AzSAShare.ShareProperties.QuotaInGB)) { + $LocalizedData.ShareURL = "https://$StorageAccountName.file.core.windows.net/$($AzSAShare.Name)" + $LocalizedData.Quota = $(if ($null -eq $AzSAShare.QuotaGiB) { $LocalizedData.Unknown } else { - Convert-DataSize -Size ($AzSAShare.ShareProperties.QuotaInGB) -DecimalPlaces 2 + Convert-DataSize -Size ($AzSAShare.QuotaGiB) }) - $LocalizedData.AccessTier = Switch ($AzSAShare.ShareProperties.AccessTier) { + $LocalizedData.AccessTier = Switch ($AzSAShare.AccessTier) { 'TransactionOptimized' { $LocalizedData.TransactionOptimized } - default {$AzSAShare.ShareProperties.AccessTier} + $null { $LocalizedData.None } + default { $AzSAShare.AccessTier } } - $LocalizedData.LastModified = $AzSAShare.LastModified.UtcDateTime.ToShortDateString() - $LocalizedData.Snapshot = $(if ($AzSAShare.IsSnapshot) { + $LocalizedData.LastModified = if ($AzSAShare.LastModifiedTime) { + $AzSAShare.LastModifiedTime.ToShortDateString() + } else { + $LocalizedData.None + } + $LocalizedData.Snapshot = $(if ($AzSAShare.SnapshotTime) { $LocalizedData.Enabled } else { $LocalizedData.Disabled diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzSATable.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzSATable.ps1 similarity index 88% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzSATable.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzSATable.ps1 index 2a7ed3c..63c1580 100644 --- a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzSATable.ps1 +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzSATable.ps1 @@ -36,7 +36,8 @@ function Get-AbrAzSATable { process { Try { - $AzSATables = Get-AzStorageAccount -ResourceGroupName $ResourceGroupName -StorageAccountName $StorageAccountName | Get-AzStorageTable -ErrorAction SilentlyContinue | Sort-Object Name + $AzStorageContext = New-AzStorageContext -StorageAccountName $StorageAccountName -UseConnectedAccount -ErrorAction SilentlyContinue + $AzSATables = Get-AzStorageTable -Context $AzStorageContext -ErrorAction SilentlyContinue | Sort-Object Name if ($AzSATables) { Write-PscriboMessage $LocalizedData.Collecting Section -Style NOTOCHeading6 -ExcludeFromTOC $LocalizedData.Heading { diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzStorageAccount.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzStorageAccount.ps1 similarity index 93% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzStorageAccount.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzStorageAccount.ps1 index e252183..e536d6b 100644 --- a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzStorageAccount.ps1 +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzStorageAccount.ps1 @@ -34,6 +34,14 @@ function Get-AbrAzStorageAccount { Paragraph $LocalizedData.SectionInfo BlankLine } + $LockMap = @{} + $AllLocks = Get-AzResourceLock -ErrorAction SilentlyContinue + foreach ($Lock in $AllLocks) { + $Key = $Lock.ResourceId.ToLower() + if (-not $LockMap.ContainsKey($Key)) { $LockMap[$Key] = @() } + $LockMap[$Key] += $Lock + } + $AzStorageAccountInfo = @() $Count = 1 foreach ($AzStorageAccount in $AzStorageAccounts) { @@ -96,6 +104,12 @@ function Get-AbrAzStorageAccount { $LocalizedData.Created = $AzStorageAccount.CreationTime } + $InObj[$LocalizedData.Locks] = $( + $rl = $LockMap[$AzStorageAccount.Id.ToLower()] + if ($rl) { ($rl | ForEach-Object { "$($_.Name) ($($_.Properties.Level))" }) -join [Environment]::NewLine } + else { $LocalizedData.None } + ) + if ($Options.ShowTags) { $InObj[$LocalizedData.Tags] = if ([string]::IsNullOrEmpty($AzStorageAccount.Tags)) { $LocalizedData.None diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzSubscription.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzSubscription.ps1 similarity index 100% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzSubscription.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzSubscription.ps1 diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzTenant.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzTenant.ps1 similarity index 100% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzTenant.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzTenant.ps1 diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzUserAssignedManagedIdentity.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzUserAssignedManagedIdentity.ps1 new file mode 100644 index 0000000..5c2145c --- /dev/null +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzUserAssignedManagedIdentity.ps1 @@ -0,0 +1,100 @@ +function Get-AbrAzUserAssignedManagedIdentity { + <# + .SYNOPSIS + Used by As Built Report to retrieve Azure User Assigned Managed Identity information + .DESCRIPTION + Documents the configuration of Azure User Assigned Managed Identities. + .NOTES + Version: 0.1.0 + Author: Tim Carman + Twitter: @tpcarman + Github: tpcarman + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param () + + begin { + $LocalizedData = $reportTranslate.GetAbrAzUserAssignedManagedIdentity + Write-PScriboMessage ($LocalizedData.InfoLevel -f $InfoLevel.UserAssignedManagedIdentity) + } + + process { + try { + if ($InfoLevel.UserAssignedManagedIdentity -ge 1) { + $AzUAMIs = Get-AzUserAssignedIdentity -ErrorAction SilentlyContinue | Sort-Object Name + if ($AzUAMIs) { + Write-PScriboMessage $LocalizedData.Collecting + Section -Style Heading4 $LocalizedData.Heading { + if ($Options.ShowSectionInfo) { + Paragraph $LocalizedData.SectionInfo + BlankLine + } + + $AzUAMIInfo = @() + foreach ($AzUAMI in $AzUAMIs) { + $InObj = [Ordered]@{ + $LocalizedData.Name = $AzUAMI.Name + $LocalizedData.ResourceGroup = $AzUAMI.ResourceGroupName + $LocalizedData.Location = $AzLocationLookup."$($AzUAMI.Location)" + $LocalizedData.Subscription = "$($AzSubscriptionLookup.(($AzUAMI.Id).split('/')[2]))" + $LocalizedData.SubscriptionID = ($AzUAMI.Id).split('/')[2] + $LocalizedData.ClientID = $AzUAMI.ClientId + $LocalizedData.PrincipalID = $AzUAMI.PrincipalId + $LocalizedData.TenantID = $AzUAMI.TenantId + } + + if ($Options.ShowTags) { + $InObj[$LocalizedData.Tags] = if ($null -eq $AzUAMI.Tags -or $AzUAMI.Tags.Count -eq 0) { + $LocalizedData.None + } else { + ($AzUAMI.Tags.GetEnumerator() | ForEach-Object { "$($_.Key):`t$($_.Value)" }) -join [Environment]::NewLine + } + } + + $AzUAMIInfo += [PSCustomObject]$InObj + } + + if ($InfoLevel.UserAssignedManagedIdentity -ge 2) { + Paragraph ($LocalizedData.ParagraphDetail -f $AzSubscription.Name) + BlankLine + foreach ($AzUAMIItem in $AzUAMIInfo) { + Section -Style NOTOCHeading5 -ExcludeFromTOC $AzUAMIItem.($LocalizedData.Name) { + $TableParams = @{ + Name = "$($LocalizedData.TableHeading) - $($AzUAMIItem.($LocalizedData.Name))" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AzUAMIItem | Table @TableParams + } + } + } else { + Paragraph ($LocalizedData.ParagraphSummary -f $AzSubscription.Name) + BlankLine + $TableParams = @{ + Name = "$($LocalizedData.TableHeading) - $($AzSubscription.Name)" + List = $false + Columns = $LocalizedData.Name, $LocalizedData.ResourceGroup, $LocalizedData.Location, $LocalizedData.ClientID + ColumnWidths = 30, 25, 20, 25 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AzUAMIInfo | Table @TableParams + } + } + } + } + } catch { + Write-PScriboMessage -IsWarning "$($LocalizedData.ErrorMessage) $($_.Exception.Message)" + } + } + + end {} +} diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzVirtualMachine.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzVirtualMachine.ps1 similarity index 100% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzVirtualMachine.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzVirtualMachine.ps1 diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzVirtualNetwork.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzVirtualNetwork.ps1 similarity index 89% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzVirtualNetwork.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzVirtualNetwork.ps1 index e3f37e8..431674e 100644 --- a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzVirtualNetwork.ps1 +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzVirtualNetwork.ps1 @@ -42,6 +42,14 @@ function Get-AbrAzVirtualNetwork { BlankLine } } + $LockMap = @{} + $AllLocks = Get-AzResourceLock -ErrorAction SilentlyContinue + foreach ($Lock in $AllLocks) { + $Key = $Lock.ResourceId.ToLower() + if (-not $LockMap.ContainsKey($Key)) { $LockMap[$Key] = @() } + $LockMap[$Key] += $Lock + } + $AzVirtualNetworkInfo = @() $Count = 1 foreach ($AzVirtualNetwork in $AzVirtualNetworks) { @@ -66,6 +74,12 @@ function Get-AbrAzVirtualNetwork { }) } + $InObj[$LocalizedData.Locks] = $( + $rl = $LockMap[$AzVirtualNetwork.Id.ToLower()] + if ($rl) { ($rl | ForEach-Object { "$($_.Name) ($($_.Properties.Level))" }) -join [Environment]::NewLine } + else { $LocalizedData.None } + ) + if ($Options.ShowTags) { $InObj[$LocalizedData.Tags] = if ([string]::IsNullOrEmpty($AzVirtualNetwork.Tag)) { $LocalizedData.None diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzVirtualNetworkGateway.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzVirtualNetworkGateway.ps1 new file mode 100644 index 0000000..dde8a35 --- /dev/null +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzVirtualNetworkGateway.ps1 @@ -0,0 +1,176 @@ +function Get-AbrAzVirtualNetworkGateway { + <# + .SYNOPSIS + Used by As Built Report to retrieve Azure Virtual Network Gateway information + .DESCRIPTION + Documents the configuration of Azure Virtual Network Gateways including gateway type, + SKU, BGP settings, active-active mode, and VPN connections. + .NOTES + Version: 0.1.0 + Author: Tim Carman + Twitter: @tpcarman + Github: tpcarman + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param () + + begin { + $LocalizedData = $reportTranslate.GetAbrAzVirtualNetworkGateway + Write-PScriboMessage ($LocalizedData.InfoLevel -f $InfoLevel.VirtualNetworkGateway) + } + + process { + try { + if ($InfoLevel.VirtualNetworkGateway -ge 1) { + $AzVNetGateways = Get-AzResource -ResourceType 'Microsoft.Network/virtualNetworkGateways' -ErrorAction SilentlyContinue | + ForEach-Object { Get-AzVirtualNetworkGateway -Name $_.Name -ResourceGroupName $_.ResourceGroupName } | + Sort-Object Name + if ($AzVNetGateways) { + Write-PScriboMessage $LocalizedData.Collecting + Section -Style Heading4 $LocalizedData.Heading { + if ($Options.ShowSectionInfo) { + Paragraph $LocalizedData.SectionInfo + BlankLine + } + + # Pre-collect all connections in the subscription for InfoLevel 2 detail + $ConnectionsMap = @{} + if ($InfoLevel.VirtualNetworkGateway -ge 2) { + $AllConnections = Get-AzResource -ResourceType 'Microsoft.Network/connections' -ErrorAction SilentlyContinue | + ForEach-Object { Get-AzVirtualNetworkGatewayConnection -Name $_.Name -ResourceGroupName $_.ResourceGroupName -ErrorAction SilentlyContinue } + foreach ($AzVNetGateway in $AzVNetGateways) { + $ConnectionsMap[$AzVNetGateway.Name] = $AllConnections | Where-Object { $_.VirtualNetworkGateway1.Id -eq $AzVNetGateway.Id } + } + } + + $LockMap = @{} + $AllLocks = Get-AzResourceLock -ErrorAction SilentlyContinue + foreach ($Lock in $AllLocks) { + $Key = $Lock.ResourceId.ToLower() + if (-not $LockMap.ContainsKey($Key)) { $LockMap[$Key] = @() } + $LockMap[$Key] += $Lock + } + + $AzVNetGatewayInfo = @() + foreach ($AzVNetGateway in $AzVNetGateways) { + $VirtualNetwork = if ($AzVNetGateway.IpConfigurations -and $AzVNetGateway.IpConfigurations[0].Subnet.Id) { + ($AzVNetGateway.IpConfigurations[0].Subnet.Id).split('/')[8] + } else { + $LocalizedData.None + } + $InObj = [Ordered]@{ + $LocalizedData.Name = $AzVNetGateway.Name + $LocalizedData.ResourceGroup = $AzVNetGateway.ResourceGroupName + $LocalizedData.Location = $AzLocationLookup."$($AzVNetGateway.Location)" + $LocalizedData.Subscription = "$($AzSubscriptionLookup.(($AzVNetGateway.Id).split('/')[2]))" + $LocalizedData.SubscriptionID = ($AzVNetGateway.Id).split('/')[2] + $LocalizedData.VirtualNetwork = $VirtualNetwork + $LocalizedData.GatewayType = $AzVNetGateway.GatewayType + $LocalizedData.VpnType = if ($AzVNetGateway.GatewayType -eq 'Vpn') { $AzVNetGateway.VpnType } else { $LocalizedData.NotApplicable } + $LocalizedData.SKU = $AzVNetGateway.Sku.Name + $LocalizedData.Generation = if ($AzVNetGateway.VpnGatewayGeneration -and $AzVNetGateway.VpnGatewayGeneration -ne 'None') { $AzVNetGateway.VpnGatewayGeneration } else { $LocalizedData.NotApplicable } + $LocalizedData.ActiveActive = $AzVNetGateway.ActiveActive + $LocalizedData.EnableBgp = $AzVNetGateway.EnableBgp + $LocalizedData.BgpAsn = if ($AzVNetGateway.EnableBgp) { $AzVNetGateway.BgpSettings.Asn } else { $LocalizedData.NotApplicable } + $LocalizedData.BgpPeeringAddress = if ($AzVNetGateway.EnableBgp) { $AzVNetGateway.BgpSettings.BgpPeeringAddress } else { $LocalizedData.NotApplicable } + $LocalizedData.ProvisioningState = $AzVNetGateway.ProvisioningState + } + + $InObj[$LocalizedData.Locks] = $( + $rl = $LockMap[$AzVNetGateway.Id.ToLower()] + if ($rl) { ($rl | ForEach-Object { "$($_.Name) ($($_.Properties.Level))" }) -join [Environment]::NewLine } + else { $LocalizedData.None } + ) + + if ($Options.ShowTags) { + $InObj[$LocalizedData.Tags] = if ($null -eq $AzVNetGateway.Tag -or $AzVNetGateway.Tag.Count -eq 0) { + $LocalizedData.None + } else { + ($AzVNetGateway.Tag.Keys | ForEach-Object { "$_`:`t$($AzVNetGateway.Tag[$_])" }) -join [Environment]::NewLine + } + } + + $AzVNetGatewayInfo += [PSCustomObject]$InObj + } + + if ($Healthcheck.VirtualNetworkGateway.ProvisioningState) { + $AzVNetGatewayInfo | Where-Object { $_.$($LocalizedData.ProvisioningState) -ne 'Succeeded' } | Set-Style -Style Critical -Property $LocalizedData.ProvisioningState + } + + if ($InfoLevel.VirtualNetworkGateway -ge 2) { + Paragraph ($LocalizedData.ParagraphDetail -f $AzSubscription.Name) + foreach ($AzVNetGateway in $AzVNetGatewayInfo) { + Section -Style NOTOCHeading5 -ExcludeFromTOC "$($AzVNetGateway.($LocalizedData.Name))" { + $TableParams = @{ + Name = "$($LocalizedData.TableHeading) - $($AzVNetGateway.($LocalizedData.Name))" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AzVNetGateway | Table @TableParams + + $AzGatewayName = $AzVNetGateway.($LocalizedData.Name) + $Connections = $ConnectionsMap[$AzGatewayName] + if ($Connections) { + Section -Style NOTOCHeading6 -ExcludeFromTOC $LocalizedData.Connections { + $ConnectionInfo = @() + foreach ($Connection in $Connections) { + $InObj = [Ordered]@{ + $LocalizedData.ConnectionName = $Connection.Name + $LocalizedData.ConnectionType = $Connection.ConnectionType + $LocalizedData.ConnectionStatus = if ($Connection.ConnectionStatus) { $Connection.ConnectionStatus } else { $LocalizedData.NotApplicable } + $LocalizedData.ConnectionProtocol = if ($Connection.ConnectionProtocol) { $Connection.ConnectionProtocol } else { $LocalizedData.NotApplicable } + $LocalizedData.RoutingWeight = $Connection.RoutingWeight + $LocalizedData.EnableBgp = $Connection.EnableBgp + $LocalizedData.ProvisioningState = $Connection.ProvisioningState + } + $ConnectionInfo += [PSCustomObject]$InObj + } + + if ($Healthcheck.VirtualNetworkGateway.ConnectionStatus) { + $ConnectionInfo | Where-Object { $_.$($LocalizedData.ConnectionStatus) -notin @('Connected', $LocalizedData.NotApplicable) } | Set-Style -Style Warning -Property $LocalizedData.ConnectionStatus + } + + $TableParams = @{ + Name = "$($LocalizedData.Connections) - $($AzGatewayName)" + List = $false + ColumnWidths = 25, 15, 15, 15, 10, 10, 10 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $ConnectionInfo | Table @TableParams + } + } + } + } + } else { + Paragraph ($LocalizedData.ParagraphSummary -f $AzSubscription.Name) + BlankLine + $TableParams = @{ + Name = "$($LocalizedData.TableHeading) - $($AzSubscription.Name)" + List = $false + Columns = $LocalizedData.Name, $LocalizedData.ResourceGroup, $LocalizedData.Location, $LocalizedData.GatewayType, $LocalizedData.SKU, $LocalizedData.ProvisioningState + ColumnWidths = 25, 20, 15, 15, 10, 15 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AzVNetGatewayInfo | Table @TableParams + } + } + } + } + } catch { + Write-PScriboMessage -IsWarning "$($LocalizedData.ErrorMessage) $($_.Exception.Message)" + } + } + + end {} +} diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzVirtualNetworkPeering.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzVirtualNetworkPeering.ps1 similarity index 100% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzVirtualNetworkPeering.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzVirtualNetworkPeering.ps1 diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzVirtualNetworkSubnet.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzVirtualNetworkSubnet.ps1 similarity index 100% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-AbrAzVirtualNetworkSubnet.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzVirtualNetworkSubnet.ps1 diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzVmScaleSet.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzVmScaleSet.ps1 new file mode 100644 index 0000000..d21a222 --- /dev/null +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-AbrAzVmScaleSet.ps1 @@ -0,0 +1,122 @@ +function Get-AbrAzVmScaleSet { + <# + .SYNOPSIS + Used by As Built Report to retrieve Azure Virtual Machine Scale Set information + .DESCRIPTION + Documents the configuration of Azure Virtual Machine Scale Sets, including SKU, + orchestration mode, upgrade policy, zones, and instance count. + .NOTES + Version: 0.1.0 + Author: Tim Carman + Twitter: @tpcarman + Github: tpcarman + .EXAMPLE + + .LINK + + #> + [CmdletBinding()] + param () + + begin { + $LocalizedData = $reportTranslate.GetAbrAzVmScaleSet + Write-PScriboMessage ($LocalizedData.InfoLevel -f $InfoLevel.VmScaleSet) + } + + process { + try { + if ($InfoLevel.VmScaleSet -ge 1) { + $AzVmScaleSets = Get-AzVmss -ErrorAction SilentlyContinue | Sort-Object Name + if ($AzVmScaleSets) { + Write-PScriboMessage $LocalizedData.Collecting + + Section -Style Heading4 $LocalizedData.Heading { + if ($Options.ShowSectionInfo) { + Paragraph $LocalizedData.SectionInfo + BlankLine + } + + $AzVmssInfo = @() + foreach ($AzVmss in $AzVmScaleSets) { + $Zones = if ($AzVmss.Zones -and $AzVmss.Zones.Count -gt 0) { + $AzVmss.Zones -join ', ' + } else { + $LocalizedData.None + } + $Identity = if ($AzVmss.Identity) { + $AzVmss.Identity.Type + } else { + $LocalizedData.None + } + $InObj = [Ordered]@{ + $LocalizedData.Name = $AzVmss.Name + $LocalizedData.ResourceGroup = $AzVmss.ResourceGroupName + $LocalizedData.Location = $AzLocationLookup."$($AzVmss.Location)" + $LocalizedData.Subscription = "$($AzSubscriptionLookup.(($AzVmss.Id).split('/')[2]))" + $LocalizedData.SubscriptionID = ($AzVmss.Id).split('/')[2] + $LocalizedData.VmSize = $AzVmss.Sku.Name + $LocalizedData.Instances = $AzVmss.Sku.Capacity + $LocalizedData.OrchestrationMode = $AzVmss.OrchestrationMode + $LocalizedData.UpgradePolicy = $AzVmss.UpgradePolicy.Mode + $LocalizedData.Overprovision = $AzVmss.Overprovision + $LocalizedData.SinglePlacementGroup = $AzVmss.SinglePlacementGroup + $LocalizedData.Zones = $Zones + $LocalizedData.Identity = $Identity + $LocalizedData.ProvisioningState = $AzVmss.ProvisioningState + } + + if ($Options.ShowTags) { + $InObj[$LocalizedData.Tags] = if ($null -eq $AzVmss.Tags -or $AzVmss.Tags.Count -eq 0) { + $LocalizedData.None + } else { + ($AzVmss.Tags.GetEnumerator() | ForEach-Object { "$($_.Name):`t$($_.Value)" }) -join [Environment]::NewLine + } + } + + $AzVmssInfo += [PSCustomObject]$InObj + } + + if ($Healthcheck.VmScaleSet.ProvisioningState) { + $AzVmssInfo | Where-Object { $_.$($LocalizedData.ProvisioningState) -ne 'Succeeded' } | Set-Style -Style Critical -Property $LocalizedData.ProvisioningState + } + + if ($InfoLevel.VmScaleSet -ge 2) { + Paragraph ($LocalizedData.ParagraphDetail -f $AzSubscription.Name) + foreach ($AzVmssItem in $AzVmssInfo) { + $VmssName = $AzVmssItem.($LocalizedData.Name) + Section -Style NOTOCHeading5 -ExcludeFromTOC $VmssName { + $TableParams = @{ + Name = "$($LocalizedData.TableHeading) - $VmssName" + List = $true + ColumnWidths = 40, 60 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AzVmssItem | Table @TableParams + } + } + } else { + Paragraph ($LocalizedData.ParagraphSummary -f $AzSubscription.Name) + BlankLine + $TableParams = @{ + Name = "$($LocalizedData.TableHeading) - $($AzSubscription.Name)" + List = $false + Columns = $LocalizedData.Name, $LocalizedData.Location, $LocalizedData.VmSize, $LocalizedData.Instances, $LocalizedData.UpgradePolicy, $LocalizedData.ProvisioningState + ColumnWidths = 25, 20, 25, 10, 10, 10 + } + if ($Report.ShowTableCaptions) { + $TableParams['Caption'] = "- $($TableParams.Name)" + } + $AzVmssInfo | Table @TableParams + } + } + } + } + } catch { + Write-PScriboMessage -IsWarning "$($LocalizedData.ErrorMessage) $($_.Exception.Message)" + } + } + + end {} +} diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-CountryName.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-CountryName.ps1 similarity index 91% rename from AsBuiltReport.Microsoft.Azure/Src/Private/Get-CountryName.ps1 rename to AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-CountryName.ps1 index 0b63243..8fbab08 100644 --- a/AsBuiltReport.Microsoft.Azure/Src/Private/Get-CountryName.ps1 +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Get-CountryName.ps1 @@ -1,4 +1,23 @@ function Get-CountryName { + <# + .SYNOPSIS + Resolves an ISO 3166-1 alpha-2 country code to a localised country name. + .DESCRIPTION + Accepts a two-letter ISO 3166-1 alpha-2 country code and returns the corresponding + country name from the active report localisation data. Input is normalised to + uppercase before lookup. Returns a localised "not found" message if the code is + not present in the lookup table. + .PARAMETER CountryCode + ISO 3166-1 alpha-2 country code (e.g. 'US', 'GB', 'DE'). Case-insensitive. + .EXAMPLE + Get-CountryName -CountryCode 'AU' + .NOTES + Version: 0.1.0 + Author: Tim Carman + Github: tpcarman + .LINK + https://github.com/AsBuiltReport/AsBuiltReport.Microsoft.Azure + #> [CmdletBinding()] param ( [Parameter(Mandatory = $true)] diff --git a/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Test-AbrAzInfoLevelEnabled.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Test-AbrAzInfoLevelEnabled.ps1 new file mode 100644 index 0000000..23d8ab2 --- /dev/null +++ b/AsBuiltReport.Microsoft.Azure/Src/Private/Report/Test-AbrAzInfoLevelEnabled.ps1 @@ -0,0 +1,56 @@ +function Test-AbrAzInfoLevelEnabled { + <# + .SYNOPSIS + Returns $true if at least one section in the provided order has a non-zero InfoLevel. + .DESCRIPTION + Iterates over a list of section names and inspects the corresponding InfoLevel value. + Simple integer InfoLevels are compared directly to zero. Complex InfoLevel objects + (e.g. Policy with Assignments/Definitions sub-keys) are summed; a non-zero sum is + treated as enabled. Returns $true as soon as the first enabled section is found, + otherwise returns $false. + .PARAMETER SectionOrder + Array of section name strings to evaluate, typically sourced from Options.SectionOrder + in the report JSON configuration. + .PARAMETER InfoLevel + The InfoLevel object or hashtable from the report JSON configuration. Each key + corresponds to a section name and holds either an integer (0-4) or a nested object. + .EXAMPLE + Test-AbrAzInfoLevelEnabled -SectionOrder $JsonConfig.Options.SectionOrder -InfoLevel $JsonConfig.InfoLevel + .NOTES + Version: 0.1.0 + Author: Tim Carman + Github: tpcarman + .LINK + https://github.com/AsBuiltReport/AsBuiltReport.Microsoft.Azure + #> + [CmdletBinding()] + [OutputType([bool])] + param ( + [Parameter(Mandatory)] + [string[]] $SectionOrder, + [Parameter(Mandatory)] + [object] $InfoLevel + ) + foreach ($SectionName in $SectionOrder) { + $level = if ($InfoLevel.PSObject.Properties.Name -contains $SectionName) { + $InfoLevel.$SectionName + } elseif ($InfoLevel -is [hashtable] -and $InfoLevel.ContainsKey($SectionName)) { + $InfoLevel[$SectionName] + } else { + continue + } + $enabled = switch ($level) { + { $_ -is [hashtable] -or $_ -is [PSCustomObject] } { + $sum = if ($_ -is [hashtable]) { + ($_.Values | Measure-Object -Sum).Sum + } else { + ($_.PSObject.Properties.Value | ForEach-Object { [int]$_ } | Measure-Object -Sum).Sum + } + $sum -gt 0 + } + default { try { [int]$_ -gt 0 } catch { $false } } + } + if ($enabled) { return $true } + } + return $false +} diff --git a/AsBuiltReport.Microsoft.Azure/Src/Public/Invoke-AsBuiltReport.Microsoft.Azure.ps1 b/AsBuiltReport.Microsoft.Azure/Src/Public/Invoke-AsBuiltReport.Microsoft.Azure.ps1 index 12414b5..2f6eb15 100644 --- a/AsBuiltReport.Microsoft.Azure/Src/Public/Invoke-AsBuiltReport.Microsoft.Azure.ps1 +++ b/AsBuiltReport.Microsoft.Azure/Src/Public/Invoke-AsBuiltReport.Microsoft.Azure.ps1 @@ -47,7 +47,7 @@ function Invoke-AsBuiltReport.Microsoft.Azure { ) # Check for required modules - Get-RequiredModule -Name 'Az' -Version '15.3.0' + Get-RequiredModule -Name 'Az' -Version '16.0.0' # Display report module information using Core function Write-ReportModuleInfo -ModuleName 'Microsoft.Azure' @@ -65,26 +65,43 @@ function Invoke-AsBuiltReport.Microsoft.Azure { # Define default section order if not specified in config $DefaultSectionOrder = @( + "ApplicationGateway", "StorageAccount", "KeyVault", "LogAnalyticsWorkspace", + "DataCollectionRule", + "DiagnosticSetting", "LoadBalancer", "ExpressRoute", + "VirtualNetworkGateway", + "DdosProtectionPlan", "VirtualNetwork", + "PublicIpAddress", + "NetworkWatcher", "NetworkSecurityGroup", "PrivateEndpoint", "IpGroup", "DnsPrivateResolver", + "DnsForwardingRuleset", + "PrivateDnsZone", "Bastion", "Policy", + "UserAssignedManagedIdentity", "Firewall", "FirewallPolicy", "RouteTable", "VirtualMachine", "AvailabilitySet", + "VmScaleSet", + "MaintenanceConfiguration", + "AutomationAccount", "RecoveryServicesVault", "SiteRecovery", - "DesktopVirtualization" + "AsrPolicy", + "AsrRecoveryPlan", + "AsrNetworkMapping", + "DesktopVirtualization", + "NetAppFiles" ) # Use custom section order if provided, otherwise use default @@ -95,11 +112,60 @@ function Invoke-AsBuiltReport.Microsoft.Azure { Write-PScriboMessage -Plugin "Module" -Message $LocalizedData.CustomOrder } + # Resource type mapping for per-subscription existence checks + $ResourceTypeMap = @{ + 'ApplicationGateway' = 'Microsoft.Network/applicationGateways' + 'AutomationAccount' = 'Microsoft.Automation/automationAccounts' + 'AvailabilitySet' = 'Microsoft.Compute/availabilitySets' + 'VmScaleSet' = 'Microsoft.Compute/virtualMachineScaleSets' + 'MaintenanceConfiguration' = 'Microsoft.Maintenance/maintenanceConfigurations' + 'Bastion' = 'Microsoft.Network/bastionHosts' + 'DataCollectionRule' = 'Microsoft.Insights/dataCollectionRules' + 'DdosProtectionPlan' = 'Microsoft.Network/ddosProtectionPlans' + 'DesktopVirtualization' = 'Microsoft.DesktopVirtualization/hostpools' + 'DnsPrivateResolver' = 'Microsoft.Network/dnsResolvers' + 'DnsForwardingRuleset' = 'Microsoft.Network/dnsForwardingRulesets' + 'ExpressRoute' = 'Microsoft.Network/expressRouteCircuits' + 'ExpressRouteCircuit' = 'Microsoft.Network/expressRouteCircuits' + 'Firewall' = 'Microsoft.Network/azureFirewalls' + 'FirewallPolicy' = 'Microsoft.Network/firewallPolicies' + 'IpGroup' = 'Microsoft.Network/ipGroups' + 'KeyVault' = 'Microsoft.KeyVault/vaults' + 'LoadBalancer' = 'Microsoft.Network/loadBalancers' + 'LogAnalyticsWorkspace' = 'Microsoft.OperationalInsights/workspaces' + 'NetAppFiles' = 'Microsoft.NetApp/netAppAccounts' + 'NetworkSecurityGroup' = 'Microsoft.Network/networkSecurityGroups' + 'DiagnosticSetting' = $null + 'Policy' = $null + 'UserAssignedManagedIdentity' = 'Microsoft.ManagedIdentity/userAssignedIdentities' + 'PrivateDnsZone' = 'Microsoft.Network/privateDnsZones' + 'PrivateEndpoint' = 'Microsoft.Network/privateEndpoints' + 'NetworkWatcher' = 'Microsoft.Network/networkWatchers' + 'PublicIpAddress' = 'Microsoft.Network/publicIPAddresses' + 'RecoveryServicesVault' = 'Microsoft.RecoveryServices/vaults' + 'RouteTable' = 'Microsoft.Network/routeTables' + 'SiteRecovery' = 'Microsoft.RecoveryServices/vaults' + 'AsrPolicy' = 'Microsoft.RecoveryServices/vaults' + 'AsrRecoveryPlan' = 'Microsoft.RecoveryServices/vaults' + 'AsrNetworkMapping' = 'Microsoft.RecoveryServices/vaults' + 'StorageAccount' = 'Microsoft.Storage/storageAccounts' + 'VirtualMachine' = 'Microsoft.Compute/virtualMachines' + 'VirtualNetwork' = 'Microsoft.Network/virtualNetworks' + 'VirtualNetworkGateway' = 'Microsoft.Network/virtualNetworkGateways' + } + # Function mapping for section names to function names $SectionFunctionMap = @{ + "ApplicationGateway" = "Get-AbrAzApplicationGateway" + "AutomationAccount" = "Get-AbrAzAutomationAccount" "AvailabilitySet" = "Get-AbrAzAvailabilitySet" + "VmScaleSet" = "Get-AbrAzVmScaleSet" + "MaintenanceConfiguration" = "Get-AbrAzMaintenanceConfiguration" "Bastion" = "Get-AbrAzBastion" + "DataCollectionRule" = "Get-AbrAzDataCollectionRule" + "DdosProtectionPlan" = "Get-AbrAzDdosProtectionPlan" "DnsPrivateResolver" = "Get-AbrAzDnsPrivateResolver" + "DnsForwardingRuleset" = "Get-AbrAzDnsForwardingRuleset" "ExpressRouteCircuit" = "Get-AbrAzExpressRouteCircuit" "ExpressRoute" = "Get-AbrAzExpressRouteCircuit" # Alias for backward compatibility "Firewall" = "Get-AbrAzFirewall" @@ -110,14 +176,25 @@ function Invoke-AsBuiltReport.Microsoft.Azure { "LoadBalancer" = "Get-AbrAzLoadBalancer" "VirtualNetwork" = "Get-AbrAzVirtualNetwork" "NetworkSecurityGroup" = "Get-AbrAzNetworkSecurityGroup" + "DiagnosticSetting" = "Get-AbrAzDiagnosticSetting" "Policy" = "Get-AbrAzPolicy" + "UserAssignedManagedIdentity" = "Get-AbrAzUserAssignedManagedIdentity" "RouteTable" = "Get-AbrAzRouteTable" + "NetworkVirtualAppliance" = "Get-AbrAzNetworkVirtualAppliance" "VirtualMachine" = "Get-AbrAzVirtualMachine" + "VirtualNetworkGateway" = "Get-AbrAzVirtualNetworkGateway" "RecoveryServicesVault" = "Get-AbrAzRecoveryServicesVault" "SiteRecovery" = "Get-AbrAsrProtectedItems" + "AsrPolicy" = "Get-AbrAzAsrPolicy" + "AsrRecoveryPlan" = "Get-AbrAzAsrRecoveryPlan" + "AsrNetworkMapping" = "Get-AbrAzAsrNetworkMapping" "StorageAccount" = "Get-AbrAzStorageAccount" + "PrivateDnsZone" = "Get-AbrAzPrivateDnsZone" "PrivateEndpoint" = "Get-AbrAzPrivateEndpoint" + "NetworkWatcher" = "Get-AbrAzNetworkWatcher" + "PublicIpAddress" = "Get-AbrAzPublicIpAddress" "DesktopVirtualization" = "Get-AbrAzDesktopVirtualization" + "NetAppFiles" = "Get-AbrAzNetAppFiles" } #region foreach loop @@ -146,15 +223,25 @@ function Invoke-AsBuiltReport.Microsoft.Azure { } if ($AzAccount) { - $AzTenant = Get-AzTenant -TenantId $TenantId - $AzLocations = Get-AzLocation + try { + $AzTenant = Get-AzTenant -TenantId $TenantId -ErrorAction Stop + $AzLocations = Get-AzLocation -ErrorAction Stop + } catch { + Write-PScriboMessage -IsWarning ($LocalizedData.AzureApiError -f $_.Exception.Message) + continue + } $AzLocationLookup = @{} foreach ($AzLocation in $AzLocations) { $AzLocationLookup.($AzLocation.Location) = $AzLocation.DisplayName } if ($AzTenant) { # Create a Lookup Hashtable for all Azure Subscriptions - $AzSubscriptions = Get-AzSubscription -TenantId $TenantId | Sort-Object Name + try { + $AzSubscriptions = Get-AzSubscription -TenantId $TenantId -ErrorAction Stop | Sort-Object Name + } catch { + Write-PScriboMessage -IsWarning ($LocalizedData.AzureApiError -f $_.Exception.Message) + continue + } $AzSubscriptionLookup = @{} foreach ($AzSubscription in $AzSubscriptions) { $AzSubscriptionLookup.($AzSubscription.SubscriptionId) = $AzSubscription.Name @@ -162,61 +249,85 @@ function Invoke-AsBuiltReport.Microsoft.Azure { # Filter Subscriptions if ($Filter.Subscription -ne "*") { - $AzSubscriptions = foreach ($AzSubscription in $Filter.Subscription) { - Get-AzSubscription -TenantId $TenantId -SubscriptionId $AzSubscription | Sort-Object Name + try { + $AzSubscriptions = foreach ($AzSubscription in $Filter.Subscription) { + Get-AzSubscription -TenantId $TenantId -SubscriptionId $AzSubscription -ErrorAction Stop | Sort-Object Name + } + } catch { + Write-PScriboMessage -IsWarning ($LocalizedData.AzureApiError -f $_.Exception.Message) + continue } } Section -Style Heading1 $($AzTenant.Name) { Get-AbrAzTenant + Get-AbrAzManagementGroup Section -Style Heading2 $LocalizedData.Subscriptions { Get-AbrAzSubscription - foreach ($AzSubscription in $AzSubscriptions) { - Section -Style Heading3 $($AzSubscription.Name) { + if (Test-AbrAzInfoLevelEnabled -SectionOrder $SectionOrder -InfoLevel $InfoLevel) { + foreach ($AzSubscription in $AzSubscriptions) { Write-PScriboMessage ($LocalizedData.SubscriptionID -f $($AzSubscription.Id)) $AzContext = Set-AzContext -Subscription $AzSubscription.Id -Tenant $TenantId - # Process sections in the order specified by SectionOrder - foreach ($SectionName in $SectionOrder) { - try { - # Get the info level for this section - $level = if ($InfoLevel.PSObject.Properties.Name -contains $SectionName) { - $InfoLevel.$SectionName - } elseif ($InfoLevel.ContainsKey($SectionName)) { - $InfoLevel[$SectionName] - } else { - Write-PScriboMessage ($LocalizedData.InfoLevelNotFound -f $SectionName) - continue - } + $SubHasResources = $false + foreach ($SectionName in ($SectionOrder | Where-Object { Test-AbrAzInfoLevelEnabled -SectionOrder @($_) -InfoLevel $InfoLevel })) { + if (-not $ResourceTypeMap.ContainsKey($SectionName)) { + $SubHasResources = $true + break + } + $ResourceType = $ResourceTypeMap[$SectionName] + if ($null -eq $ResourceType) { continue } + if (Get-AzResource -ResourceType $ResourceType -ErrorAction SilentlyContinue | Select-Object -First 1) { + $SubHasResources = $true + break + } + } - # Determine if section is enabled and execute function - $enabled = switch ($level) { - { $_ -is [hashtable] -or $_ -is [PSCustomObject] } { - # For complex objects, sum all property values - $sum = if ($_ -is [hashtable]) { - ($_.Values | Measure-Object -Sum).Sum + if ($SubHasResources) { + Section -Style Heading3 $($AzSubscription.Name) { + # Process sections in the order specified by SectionOrder + foreach ($SectionName in $SectionOrder) { + try { + # Get the info level for this section + $level = if ($InfoLevel.PSObject.Properties.Name -contains $SectionName) { + $InfoLevel.$SectionName + } elseif ($InfoLevel.ContainsKey($SectionName)) { + $InfoLevel[$SectionName] } else { - ($_.PSObject.Properties.Value | ForEach-Object { [int]$_ } | Measure-Object -Sum).Sum + Write-PScriboMessage ($LocalizedData.InfoLevelNotFound -f $SectionName) + continue } - $sum -gt 0 - } - default { - # For simple types (int, int64, string), convert to int and check if > 0 - try { [int]$_ -gt 0 } catch { $false } - } - } - if ($enabled) { - $functionName = $SectionFunctionMap[$SectionName] - if ($functionName -and (Get-Command $functionName -ErrorAction SilentlyContinue)) { - & $functionName - } else { - Write-PScriboMessage ($LocalizedData.FunctionNotFound -f $functionName, $SectionName) + # Determine if section is enabled and execute function + $enabled = switch ($level) { + { $_ -is [hashtable] -or $_ -is [PSCustomObject] } { + # For complex objects, sum all property values + $sum = if ($_ -is [hashtable]) { + ($_.Values | Measure-Object -Sum).Sum + } else { + ($_.PSObject.Properties.Value | ForEach-Object { [int]$_ } | Measure-Object -Sum).Sum + } + $sum -gt 0 + } + default { + # For simple types (int, int64, string), convert to int and check if > 0 + try { [int]$_ -gt 0 } catch { $false } + } + } + + if ($enabled) { + $functionName = $SectionFunctionMap[$SectionName] + if ($functionName -and (Get-Command $functionName -ErrorAction SilentlyContinue)) { + & $functionName + } else { + Write-PScriboMessage ($LocalizedData.FunctionNotFound -f $functionName, $SectionName) + } + } + } catch { + Write-PScriboMessage ($LocalizedData.ErrorProcessing -f $SectionName, $_) } } - } catch { - Write-PScriboMessage ($LocalizedData.ErrorProcessing -f $SectionName, $_) } } } diff --git a/CHANGELOG.md b/CHANGELOG.md index 11a6fab..223eef9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,53 @@ # :arrows_clockwise: Microsoft Azure As Built Report Changelog +## [0.3.0] - 2026-07-13 + +### Added +* Add InfoLevel 2 detail view for ASR protected items, showing per-VM sections with replication provider, health, state, active/target locations, test failover status, and A2A-specific RPO, last heartbeat, recovery VM size, and availability zone properties +* Add support for ASR Replication Policies (`AsrPolicy`) with summary table at InfoLevel 1 and per-policy detail at InfoLevel 2; `AppConsistentSnapshot` health check warns when app-consistent snapshot frequency is disabled +* Add support for ASR Recovery Plans (`AsrRecoveryPlan`) with summary table at InfoLevel 1 and per-plan detail at InfoLevel 2 +* Add support for ASR Network Mappings (`AsrNetworkMapping`) with summary table at InfoLevel 1; `MappingState` health check warns on non-Paired mappings +* Add `StorageRedundancy`, `CrossRegionRestore`, `SoftDeleteState`, `SoftDeleteRetentionDays`, `ImmutabilityState`, and `PublicNetworkAccess` properties to Recovery Services Vault detail view +* Add `SoftDeleteEnabled`, `ImmutabilityEnabled`, and `PublicNetworkAccess` health checks to Recovery Services Vault +* Add support for Azure NetApp Files (NetApp Accounts, Capacity Pools, Volumes, Snapshot Policies, Backup Policies) with per-volume detail, Active Directory and encryption configuration, mount targets, export policy rules, and 5 health checks (pool allocation, AD join status, snapshot policy attachment, backup policy attachment, customer-managed key usage) +* Add support for Management Groups, displaying the full hierarchy with parent/child relationships and direct subscription counts +* Add optional Management Group hierarchy diagram (`Options.EnableDiagrams: true`) using the AsBuiltReport.Diagram module, showing management group nodes with subscription collections sized to fit a portrait page +* Add `Options.DiagramDpi` setting to control the raster output resolution of generated diagrams +* Add support for Private DNS Zones, including record set and virtual network link counts with per-zone detail and virtual network link sub-sections at InfoLevel 2 +* Add support for Virtual Network Gateways, including gateway type, SKU, BGP settings, active-active mode, generation, and VPN connection detail at InfoLevel 2 +* Add support for DDoS Protection Plans, including protected virtual network count and per-plan protected VNet detail at InfoLevel 2 +* Add support for Application Gateways, including SKU, WAF mode, HTTP/2, and per-gateway HTTP listener, backend pool, and request routing rule detail at InfoLevel 2 +* Add support for Data Collection Rules, including data source types, Log Analytics destination count, and per-rule destination and data flow detail at InfoLevel 2 +* Add support for Public IP Addresses, including SKU, allocation method, IP version, DNS settings, availability zones, and associated resource, with unattached IP health check +* Add support for Network Watchers and NSG Flow Logs, including retention policy, traffic analytics enablement, and storage account, with health checks for watcher provisioning state and disabled flow logs +* Add support for VM Scale Sets, including VM size, instance count, orchestration mode, upgrade policy, availability zones, overprovision, single placement group, and identity +* Add support for Maintenance Configurations, including scope, visibility, maintenance window start time, expiration, duration, recurrence, and timezone +* Add support for DNS Forwarding Rulesets, including outbound endpoint associations, per-ruleset forwarding rules with target DNS servers, and virtual network links at InfoLevel 2 +* Add Resource Locks reporting to Virtual Networks, Key Vaults, Recovery Services Vaults, Storage Accounts, Firewalls, Private DNS Zones, Route Tables, Virtual Network Gateways, Log Analytics Workspaces, and DDoS Protection Plans; lock name and level (CanNotDelete/ReadOnly) displayed at InfoLevel 2 and above +* Add support for User Assigned Managed Identities, displaying Client ID, Principal ID, and Tenant ID with per-identity detail at InfoLevel 2 +* Add support for Automation Accounts, including account state health check and per-account Runbooks, Variables, Schedules, and Credentials sub-sections at InfoLevel 2 +* Add support for Diagnostic Settings via cross-resource sweep, displaying Log Analytics workspace, storage account, and Event Hub destinations alongside enabled log category count and metrics status; settings with no log categories enabled flagged as a health check +* Add support for Network Virtual Appliances (`Get-AbrAzNetworkVirtualAppliance`) + — identifies third-party NVAs (Palo Alto, Fortinet, Cisco, Check Point, F5, Barracuda, + SonicWall, Juniper, Riverbed) via Marketplace image publisher with optional tag-based + fallback (`Options.NvaTag`). InfoLevel 3 cross-references associated UDR route tables, + matching against all NIC private IPs on the appliance as well as the frontend private + IP of any Load Balancer fronting an NVA HA pair. Configurable publisher list via + `Options.NvaPublishers`. + +### Changed +* Update minimum Az module version requirement from 15.3.0 to 16.0.0 + +### Fixed +* Fix `Get-AbrAsrProtectedItems` - Remove A2A-only filter so all replication providers (HyperV2Azure, InMageAzureV2, etc.) are included in the report +* Fix `Get-AbrAsrProtectedItems` - Correct `FailoverHealth` health check direction: now highlights items where test failover has failed (Critical); new `NoTestFailover` health check warns on items with no test failover performed +* Fix empty per-subscription sections appearing in the report when all enabled resource types have no matching resources in a given subscription +* Fix `Get-AbrAsrProtectedItems` - Correct `ParagraghSummary` typo to `ParagraphSummary` in all language files, which caused the introductory paragraph to render empty +* Fix `Get-AbrAzSAShare` and `Get-AbrAzSAContainer` - Switch from data plane API (`Get-AzStorageShare`, `Get-AzStorageContainer`) to ARM management plane (`Get-AzRmStorageShare`, `Get-AzRmStorageContainer`) to resolve 403 Forbidden errors when storage account shared key access is disabled +* Fix `Get-AbrAzSAQueue` and `Get-AbrAzSATable` - Use `New-AzStorageContext -UseConnectedAccount` for OAuth-based data plane access to resolve 403 Forbidden errors when storage account shared key access is disabled +* Fix unhandled `Error while copying content to a stream` exception in `Invoke-AsBuiltReport.Microsoft.Azure` caused by `Get-AzTenant`, `Get-AzLocation`, and `Get-AzSubscription` being called without error handling after authentication; failures are now caught and reported as warnings +* Fix `Get-AbrAzLoadBalancer` - Correct `LoadBalancerImage` to `Image` in all language files; the mismatched localization key caused the Load Balancer architecture diagram to fail rendering and fall back to the `ImageError` message + ## [0.2.0] - 2026-02-11 ### Added diff --git a/LICENSE b/LICENSE index d8002d2..53f3c82 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2025 AsBuiltReport +Copyright (c) 2026 AsBuiltReport Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 2d4097c..7be874e 100644 --- a/README.md +++ b/README.md @@ -46,24 +46,40 @@ Please refer to the AsBuiltReport [website](https://www.asbuiltreport.com) for m The Microsoft Azure As Built Report currently supports reporting for the following Azure resources; +* Application Gateways +* Automation Accounts * Availability Sets * Bastion Hosts +* Data Collection Rules +* DDoS Protection Plans * Desktop Virtualization +* Diagnostic Settings +* DNS Forwarding Rulesets * ExpressRoute Circuits -* Firewalls * Firewall Policies +* Firewalls * IP Groups * Key Vaults * Load Balancers * Log Analytics Workspaces +* Maintenance Configurations +* Management Groups +* NetApp Files +* Network Virtual Appliances +* Network Watchers * Policies * Private DNS Resolvers +* Private DNS Zones * Private Endpoints +* Public IP Addresses * Route Tables * Storage Accounts * Subscriptions * Tenants +* User Assigned Managed Identities +* Virtual Machine Scale Sets * Virtual Machines +* Virtual Network Gateways * Virtual Networks # :beginner: Getting Started @@ -81,13 +97,13 @@ This report is compatible with the following PowerShell versions; The Microsoft Azure As Built Report supports the following languages; -| Language | Culture Code | -|----------|--------------| +| Language | Culture Code | +|--------------|-----------------| | English (US) | en-US (Default) | -| English (GB) | en-GB | -| French | fr-FR | -| German | de-DE | -| Spanish | es-ES | +| English (GB) | en-GB | +| French | fr-FR | +| German | de-DE | +| Spanish | es-ES | ## :wrench: System Requirements @@ -198,11 +214,11 @@ New-AsBuiltReport -Report Microsoft.Azure -Target $TenantId ` Open a PowerShell terminal window and install each of the required modules. > [!NOTE] -> Microsoft Az 15.2.0 or higher is required. Please ensure older Az modules have been uninstalled. +> Microsoft Az 16.0.0 or higher is required. Please ensure older Az modules have been uninstalled. ```powershell # Install -install-module Az -Repository PSGallery -MinimumVersion 15.3.0 -Force +install-module Az -Repository PSGallery -MinimumVersion 16.0.0 -Force install-module AsBuiltReport.Microsoft.Azure -Repository PSGallery -Force # Update @@ -260,10 +276,16 @@ The **Report** schema provides configuration of the Microsoft Azure report infor ### Options The **Options** schema allows certain options within the report to be toggled on or off. -| Sub-Schema | Setting | Default | Description | -|-----------------|--------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| ShowSectionInfo | true / false | true | Toggle to enable/disable information relating to Azure resources within each section. | -| ShowTags | true / false | true | Toggle to enable/disable the display of Azure resource tags.

_**Note:** Reporting of tags is not currently available on all Azure resources. Tags will only be displayed for Azure resources when the relevant section [InfoLevel](#infolevel) is configured to 2 or higher._ | +| Sub-Schema | Setting | Default | Description | +|-----------------|-------------------------------|---------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ShowSectionInfo | true / false | true | Toggle to enable/disable information relating to Azure resources within each section. | +| ShowTags | true / false | true | Toggle to enable/disable the display of Azure resource tags.

_**Note:** Reporting of tags is not currently available on all Azure resources. Tags will only be displayed for Azure resources when the relevant section [InfoLevel](#infolevel) is configured to 2 or higher._ | +| EnableDiagrams | true / false | true | Toggle to enable/disable diagram generation. Requires the [AsBuiltReport.Diagram](https://github.com/AsBuiltReport/AsBuiltReport.Diagram) module. | +| DiagramTheme | White / Black | White | Sets the colour theme for generated diagrams. | +| DiagramDpi | 72 - 600 | 600 | Sets the raster output resolution (dots per inch) for generated diagrams. Higher values increase image sharpness without changing the printed size on the page. Requires [AsBuiltReport.Diagram](https://github.com/AsBuiltReport/AsBuiltReport.Diagram) 1.0.8 or later. | +| NvaPublishers | Array of Marketplace publisher ID strings | Built-in list of 10 vendors | Overrides the list of Azure Marketplace VM image publisher IDs used to identify Network Virtual Appliances (NVAs). Omit or provide an empty array to use the default list: `paloaltonetworks`, `fortinet`, `cisco`, `checkpoint`, `f5-networks`, `barracudanetworks`, `sonicwall-inc`, `juniper-networks`, `viptela`, `riverbed`. | +| NvaTag | `key` or `key=value` | (none) | Identifies additional NVAs by resource tag as a fallback to Marketplace publisher detection. Specifying `key` alone matches any VM with that tag present; specifying `key=value` requires an exact value match. | +| SectionOrder | Array of section name strings | Default order | Controls the order in which per-subscription resource sections appear in the report. Omit the setting or provide an empty array to use the default order. Any section name omitted from the array will not be rendered, regardless of its [InfoLevel](#infolevel) setting. Valid section names: `ApplicationGateway`, `AsrNetworkMapping`, `AsrPolicy`, `AsrRecoveryPlan`, `AutomationAccount`, `AvailabilitySet`, `Bastion`, `DataCollectionRule`, `DdosProtectionPlan`, `DesktopVirtualization`, `DiagnosticSetting`, `DnsForwardingRuleset`, `DnsPrivateResolver`, `ExpressRoute`, `Firewall`, `FirewallPolicy`, `IpGroup`, `KeyVault`, `LoadBalancer`, `LogAnalyticsWorkspace`, `MaintenanceConfiguration`, `NetAppFiles`, `NetworkSecurityGroup`, `NetworkVirtualAppliance`, `NetworkWatcher`, `Policy`, `PrivateDnsZone`, `PrivateEndpoint`, `PublicIpAddress`, `RecoveryServicesVault`, `RouteTable`, `SiteRecovery`, `StorageAccount`, `UserAssignedManagedIdentity`, `VirtualMachine`, `VirtualNetwork`, `VirtualNetworkGateway`, `VmScaleSet`. | ### Filter The **Filter** schema allows report content to be filtered to specific Azure subscriptions within a tenant. @@ -302,94 +324,171 @@ There are 5 levels (0-4) of detail granularity for each section as follows; The table below outlines the default and maximum **InfoLevel** settings for each section. -| Sub-Schema | Default Setting | Maximum Setting | -|-----------------------|:---------------:|:---------------:| -| AvailabilitySet | 1 | 1 | -| Bastion | 1 | 2 | -| DesktopVirtualization | 1 | 4 | -| DnsPrivateResolver | 1 | 2 | -| ExpressRoute | 1 | 2 | -| Firewall | 1 | 3 | -| FirewallPolicy | 1 | 4 | -| IpGroup | 1 | 2 | -| KeyVault | 1 | 1 | -| LoadBalancer | 1 | 2 | -| LogAnalyticsWorkspace | 1 | 2 | -| NetworkSecurityGroup | 1 | 2 | -| Policy > Assignments | 1 | 2 | -| Policy > Definitions | 0 | 1 | -| RecoveryServicesVault | 1 | 2 | -| RouteTable | 1 | 2 | -| SiteRecovery | 1 | 1 | -| StorageAccount | 1 | 2 | -| Subscription | 1 | 1 | -| Tenant | 1 | 1 | -| VirtualNetwork | 1 | 2 | -| VirtualMachine | 1 | 2 | +| Sub-Schema | Default Setting | Maximum Setting | +|-----------------------------|:---------------:|:---------------:| +| ApplicationGateway | 1 | 2 | +| AsrNetworkMapping | 1 | 1 | +| AsrPolicy | 1 | 2 | +| AsrRecoveryPlan | 1 | 2 | +| AutomationAccount | 1 | 2 | +| AvailabilitySet | 1 | 1 | +| Bastion | 1 | 2 | +| DataCollectionRule | 1 | 2 | +| DdosProtectionPlan | 1 | 2 | +| DesktopVirtualization | 1 | 4 | +| DiagnosticSetting | 1 | 2 | +| DnsForwardingRuleset | 1 | 2 | +| DnsPrivateResolver | 1 | 2 | +| ExpressRoute | 1 | 2 | +| Firewall | 1 | 3 | +| FirewallPolicy | 1 | 4 | +| IpGroup | 1 | 2 | +| KeyVault | 1 | 1 | +| LoadBalancer | 1 | 2 | +| LogAnalyticsWorkspace | 1 | 2 | +| MaintenanceConfiguration | 1 | 2 | +| ManagementGroup | 1 | 1 | +| NetAppFiles | 1 | 4 | +| NetworkSecurityGroup | 1 | 2 | +| NetworkVirtualAppliance | 1 | 3 | +| NetworkWatcher | 1 | 2 | +| Policy > Assignments | 1 | 2 | +| Policy > Definitions | 0 | 1 | +| PrivateDnsZone | 1 | 2 | +| PublicIpAddress | 1 | 2 | +| RecoveryServicesVault | 1 | 2 | +| RouteTable | 1 | 2 | +| SiteRecovery | 1 | 2 | +| StorageAccount | 1 | 2 | +| Subscription | 1 | 1 | +| Tenant | 1 | 1 | +| UserAssignedManagedIdentity | 1 | 2 | +| VirtualMachine | 1 | 2 | +| VirtualNetwork | 1 | 2 | +| VirtualNetworkGateway | 1 | 2 | +| VmScaleSet | 1 | 2 | ### Healthcheck The **Healthcheck** schema is used to toggle health checks on or off. +#### ApplicationGateway +The **ApplicationGateway** schema is used to configure health checks for Azure Application Gateways. + +| Sub-Schema | Setting | Default | Description | Highlight | +|-------------------|--------------|---------|-----------------------------------------------------------------|-------------------------------------------------------------------------------------------| +| ProvisioningState | true / false | true | Highlights Application Gateways in a failed provisioning state | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) Provisioning is in a critical state | +| OperationalState | true / false | true | Highlights Application Gateways that are not in a Running state | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) Gateway is not in Running state | + +#### AsrNetworkMapping +The **AsrNetworkMapping** schema is used to configure health checks for Azure Site Recovery Network Mappings. + +| Sub-Schema | Setting | Default | Description | Highlight | +|--------------|--------------|---------|----------------------------------------------------------------|------------------------------------------------------------------------------------| +| MappingState | true / false | true | Highlights ASR network mappings that are not in a Paired state | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) Network mapping is not Paired | + +#### AsrPolicy +The **AsrPolicy** schema is used to configure health checks for Azure Site Recovery Replication Policies. + +| Sub-Schema | Setting | Default | Description | Highlight | +|-----------------------|--------------|---------|------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------| +| AppConsistentSnapshot | true / false | true | Highlights replication policies where app-consistent snapshot frequency is disabled (set to 0) | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) App-consistent snapshots are disabled | + +#### AutomationAccount +The **AutomationAccount** schema is used to configure health checks for Azure Automation Accounts. + +| Sub-Schema | Setting | Default | Description | Highlight | +|------------|--------------|---------|---------------------------------------------------------------|-------------------------------------------------------------------------------------------| +| State | true / false | true | Highlights Automation Accounts not in an Ok operational state | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) Provisioning is in a critical state | + #### Bastion The **Bastion** schema is used to configure health checks for Azure Bastion. -| Sub-Schema | Setting | Default | Description | Highlight | -|-------------------|--------------|---------|-------------------------------------------------------------|---------------------------------------------------------------------------------------------| +| Sub-Schema | Setting | Default | Description | Highlight | +|-------------------|--------------|---------|-------------------------------------------------------------|-------------------------------------------------------------------------------------------| | ProvisioningState | true / false | true | Highlights Bastion instances in a failed provisioning state | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) Provisioning is in a critical state | +#### DataCollectionRule +The **DataCollectionRule** schema is used to configure health checks for Azure Data Collection Rules. + +| Sub-Schema | Setting | Default | Description | Highlight | +|-------------------|--------------|---------|-----------------------------------------------------------------|-------------------------------------------------------------------------------------------| +| ProvisioningState | true / false | true | Highlights Data Collection Rules in a failed provisioning state | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) Provisioning is in a critical state | + +#### DdosProtectionPlan +The **DdosProtectionPlan** schema is used to configure health checks for Azure DDoS Protection Plans. + +| Sub-Schema | Setting | Default | Description | Highlight | +|-------------------|--------------|---------|-----------------------------------------------------------------|-------------------------------------------------------------------------------------------| +| ProvisioningState | true / false | true | Highlights DDoS Protection Plans in a failed provisioning state | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) Provisioning is in a critical state | + #### DesktopVirtualization The **DesktopVirtualization** schema is used to configure health checks for Azure Virtual Desktop. -| Sub-Schema | Setting | Default | Description | Highlight | -|--------------------|--------------|---------|--------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------| -| SessionHostHealth | true / false | true | Highlights session hosts not in Available status or with failed health checks | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) Session host is unavailable or unhealthy | -| DrainMode | true / false | true | Highlights session hosts with drain mode enabled (not accepting new sessions) | ![Info](https://placehold.co/15x15/D4E4F7/D4E4F7) Session host is in drain mode | -| RegistrationExpiry | true / false | true | Highlights host pools with expired registration tokens | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) Registration token has expired | -| NoSessionHosts | true / false | true | Warns when a host pool has no session hosts configured | Displays warning message in report | -| HostPoolCapacity | true / false | true | Warns when a host pool is at maximum session capacity | Displays warning message in report | +| Sub-Schema | Setting | Default | Description | Highlight | +|--------------------|--------------|---------|-------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------| +| SessionHostHealth | true / false | true | Highlights session hosts not in Available status or with failed health checks | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) Session host is unavailable or unhealthy | +| DrainMode | true / false | true | Highlights session hosts with drain mode enabled (not accepting new sessions) | ![Info](https://placehold.co/15x15/D4E4F7/D4E4F7) Session host is in drain mode | +| RegistrationExpiry | true / false | true | Highlights host pools with expired registration tokens | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) Registration token has expired | +| NoSessionHosts | true / false | true | Warns when a host pool has no session hosts configured | Displays warning message in report | +| HostPoolCapacity | true / false | true | Warns when a host pool is at maximum session capacity | Displays warning message in report | + +#### DiagnosticSetting +The **DiagnosticSetting** schema is used to configure health checks for Azure Diagnostic Settings. + +| Sub-Schema | Setting | Default | Description | Highlight | +|---------------|--------------|---------|---------------------------------------------------------------|------------------------------------------------------------------------------------| +| NoLogsEnabled | true / false | true | Highlights Diagnostic Settings with no log categories enabled | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) No log categories are enabled | + +#### DnsForwardingRuleset +The **DnsForwardingRuleset** schema is used to configure health checks for Azure DNS Forwarding Rulesets. + +| Sub-Schema | Setting | Default | Description | Highlight | +|---------------------|--------------|---------|-------------------------------------------------------------------|-------------------------------------------------------------------------------------------| +| ProvisioningState | true / false | true | Highlights DNS Forwarding Rulesets in a failed provisioning state | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) Provisioning is in a critical state | +| ForwardingRuleState | true / false | true | Highlights forwarding rules that are not in an Enabled state | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) Forwarding rule is not enabled | #### DnsPrivateResolver The **DnsPrivateResolver** schema is used to configure health checks for Azure DNS Private Resolver. -| Sub-Schema | Setting | Default | Description | Highlight | -|-------------------|--------------|---------|-----------------------------------------------------------------|----------------------------------------------------------------------------------------------| +| Sub-Schema | Setting | Default | Description | Highlight | +|-------------------|--------------|---------|-----------------------------------------------------------------|--------------------------------------------------------------------------------------------| | ProvisioningState | true / false | true | Highlights DNS Private Resolvers in a failed provisioning state | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) Provisioning is in a critical state | | CurrentState | true / false | true | Highlights DNS Private Resolvers not in a Connected state | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) DNS Private Resolver is not Connected | #### ExpressRoute The **ExpressRoute** schema is used to configure health checks for Azure ExpressRoute. -| Sub-Schema | Setting | Default | Description | Highlight | -|---------------|--------------|---------|-----------------------------------------------------|------------------------------------------------------------------------------------------| +| Sub-Schema | Setting | Default | Description | Highlight | +|---------------|--------------|---------|-----------------------------------------------------|----------------------------------------------------------------------------------------| | CircuitStatus | true / false | true | Highlights ExpressRoute circuits which are disabled | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) ExpressRoute circuit is disabled | #### Firewall The **Firewall** schema is used to configure health checks for Azure Firewall. -| Sub-Schema | Setting | Default | Description | Highlight | -|-------------------|--------------|---------|-----------------------------------------------------|---------------------------------------------------------------------------------------------| +| Sub-Schema | Setting | Default | Description | Highlight | +|-------------------|--------------|---------|-----------------------------------------------------|-------------------------------------------------------------------------------------------| | ProvisioningState | true / false | true | Highlights Firewalls in a failed provisioning state | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) Provisioning is in a critical state | #### FirewallPolicy The **FirewallPolicy** schema is used to configure health checks for Azure Firewall Policy. -| Sub-Schema | Setting | Default | Description | Highlight | -|-------------------|--------------|---------|----------------------------------------------------------------|---------------------------------------------------------------------------------------------| +| Sub-Schema | Setting | Default | Description | Highlight | +|-------------------|--------------|---------|----------------------------------------------------------------|-------------------------------------------------------------------------------------------| | ProvisioningState | true / false | true | Highlights Firewall Policies in a failed provisioning state | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) Provisioning is in a critical state | | ThreatIntelMode | true / false | true | Highlights Firewall Policies with Threat Intelligence disabled | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) Threat Intelligence is disabled | #### IpGroup The **IpGroup** schema is used to configure health checks for Azure IP Groups. -| Sub-Schema | Setting | Default | Description | Highlight | -|-------------------|--------------|---------|-----------------------------------------------------|---------------------------------------------------------------------------------------------| +| Sub-Schema | Setting | Default | Description | Highlight | +|-------------------|--------------|---------|-----------------------------------------------------|-------------------------------------------------------------------------------------------| | ProvisioningState | true / false | true | Highlights IP Groups in a failed provisioning state | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) Provisioning is in a critical state | #### KeyVault The **KeyVault** schema is used to configure health checks for Azure Key Vault. -| Sub-Schema | Setting | Default | Description | Highlight | -|---------------------|--------------|---------|----------------------------------------------------------|-----------------------------------------------------------------------------------------| +| Sub-Schema | Setting | Default | Description | Highlight | +|---------------------|--------------|---------|----------------------------------------------------------|---------------------------------------------------------------------------------------| | SoftDelete | true / false | true | Highlights Key Vaults without soft delete enabled | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) Soft delete is disabled | | PurgeProtection | true / false | true | Highlights Key Vaults without purge protection enabled | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) Purge protection is disabled | | PublicNetworkAccess | true / false | true | Highlights Key Vaults with public network access enabled | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) Public network access is enabled | @@ -398,63 +497,109 @@ The **KeyVault** schema is used to configure health checks for Azure Key Vault. #### LoadBalancer The **LoadBalancer** schema is used to configure health checks for Azure Load Balancer. -| Sub-Schema | Setting | Default | Description | Highlight | -|-------------------|--------------|---------|----------------------------------------------------------|---------------------------------------------------------------------------------------------| +| Sub-Schema | Setting | Default | Description | Highlight | +|-------------------|--------------|---------|----------------------------------------------------------|-------------------------------------------------------------------------------------------| | ProvisioningState | true / false | true | Highlights Load Balancers in a failed provisioning state | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) Provisioning is in a critical state | #### LogAnalyticsWorkspace The **LogAnalyticsWorkspace** schema is used to configure health checks for Azure Log Analytics Workspace. -| Sub-Schema | Setting | Default | Description | Highlight | -|---------------------------------|--------------|---------|------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------| +| Sub-Schema | Setting | Default | Description | Highlight | +|---------------------------------|--------------|---------|------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------| | ProvisioningState | true / false | true | Highlights workspaces which are in a critical state | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) Provisioning is in a critical state | | PublicNetworkAccessForIngestion | true / false | true | Highlights workspaces which have public network access enabled for ingestion | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) Public network access for ingestion is enabled | | PublicNetworkAccessForQuery | true / false | true | Highlights workspaces which have public network access enabled for query | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) Public network access for query is enabled | +#### NetAppFiles +The **NetAppFiles** schema is used to configure health checks for Azure NetApp Files. + +| Sub-Schema | Setting | Default | Description | Highlight | +|--------------------|--------------|---------|------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------| +| PoolCapacity | true / false | true | Highlights capacity pools where the sum of volume quotas exceeds 85% of pool size | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) Capacity pool is nearly fully allocated | +| AdHealth | true / false | true | Highlights NetApp Accounts with Active Directory configurations not in InUse state | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) Active Directory join is unhealthy | +| SnapshotPolicy | true / false | true | Highlights volumes with no snapshot policy attached | ![Info](https://placehold.co/15x15/D4E4F7/D4E4F7) Volume has no snapshot policy | +| BackupProtection | true / false | true | Highlights volumes with no backup policy attached | ![Info](https://placehold.co/15x15/D4E4F7/D4E4F7) Volume has no backup protection | +| CustomerManagedKey | true / false | true | Highlights NetApp Accounts using platform-managed encryption keys | ![Info](https://placehold.co/15x15/D4E4F7/D4E4F7) Account is not using customer-managed keys | + #### NetworkSecurityGroup The **NetworkSecurityGroup** schema is used to configure health checks for Azure Network Security Groups. -| Sub-Schema | Setting | Default | Description | Highlight | -|-----------------------|--------------|---------|---------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------| +| Sub-Schema | Setting | Default | Description | Highlight | +|-----------------------|--------------|---------|---------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------| | ProvisioningState | true / false | true | Highlights NSGs in a failed provisioning state | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) Provisioning is in a critical state | | OverlyPermissiveRules | true / false | true | Highlights NSG rules with overly permissive source addresses (*, 0.0.0.0/0, Internet) | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) Rule has overly permissive source address | +#### NetworkVirtualAppliance +The **NetworkVirtualAppliance** schema is used to configure health checks for Azure Network Virtual Appliances. + +| Sub-Schema | Setting | Default | Description | Highlight | +|------------|--------------|---------|---------------------------------------------|----------------------------------------------------------------------------------------| +| Status | true / false | true | Highlights Network Virtual Appliances that are deallocated | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) NVA is in a deallocated state | + +#### NetworkWatcher +The **NetworkWatcher** schema is used to configure health checks for Azure Network Watchers. + +| Sub-Schema | Setting | Default | Description | Highlight | +|-------------------|--------------|---------|------------------------------------------------------------|-------------------------------------------------------------------------------------------| +| ProvisioningState | true / false | true | Highlights Network Watchers in a failed provisioning state | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) Provisioning is in a critical state | +| FlowLogEnabled | true / false | true | Highlights NSG Flow Logs that are not enabled | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) Flow log is not enabled | + +#### PrivateDnsZone +The **PrivateDnsZone** schema is used to configure health checks for Azure Private DNS Zones. + +| Sub-Schema | Setting | Default | Description | Highlight | +|---------------------|--------------|---------|-----------------------------------------------------------------------|-------------------------------------------------------------------------------------------| +| ProvisioningState | true / false | true | Highlights Private DNS Zones in a failed provisioning state | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) Provisioning is in a critical state | +| VirtualNetworkLinks | true / false | true | Highlights Private DNS Zones with no virtual network links configured | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) No virtual network links configured | + #### PrivateEndpoint The **PrivateEndpoint** schema is used to configure health checks for Azure Private Endpoints. -| Sub-Schema | Setting | Default | Description | Highlight | -|-------------------|--------------|---------|------------------------------------------------------------------|---------------------------------------------------------------------------------------------| +| Sub-Schema | Setting | Default | Description | Highlight | +|-------------------|--------------|---------|------------------------------------------------------------------|-------------------------------------------------------------------------------------------| | ProvisioningState | true / false | true | Highlights Private Endpoints in a failed provisioning state | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) Provisioning is in a critical state | | ConnectionStatus | true / false | true | Highlights Private Endpoints with connection status not Approved | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) Connection is not Approved | +#### PublicIpAddress +The **PublicIpAddress** schema is used to configure health checks for Azure Public IP Addresses. + +| Sub-Schema | Setting | Default | Description | Highlight | +|-------------------|--------------|---------|-----------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------| +| ProvisioningState | true / false | true | Highlights Public IP Addresses in a failed provisioning state | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) Provisioning is in a critical state | +| Unattached | true / false | true | Highlights Public IP Addresses not associated with any resource (potential waste) | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) IP address is not associated with any resource | + #### RecoveryServicesVault The **RecoveryServicesVault** schema is used to configure health checks for Azure Recovery Services Vault. -| Sub-Schema | Setting | Default | Description | Highlight | -|-------------------------------|--------------|---------|--------------------------------------------------------------------|------------------------------------------------------------------------------------------------------| +| Sub-Schema | Setting | Default | Description | Highlight | +|-------------------------------|--------------|---------|--------------------------------------------------------------------|----------------------------------------------------------------------------------------------------| | ProvisioningState | true / false | true | Highlights Recovery Services Vaults in a failed provisioning state | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) Provisioning is in a critical state | | PrivateEndpointStateForBackup | true / false | true | Highlights vaults without private endpoints configured for backup | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) Private endpoint for backup is not configured | +| SoftDeleteEnabled | true / false | true | Highlights vaults where soft delete is disabled | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) Soft delete is disabled | +| ImmutabilityEnabled | true / false | true | Highlights vaults where immutability is not enabled | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) Vault immutability is not enabled | +| PublicNetworkAccess | true / false | true | Highlights vaults with public network access enabled | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) Public network access is enabled | #### RouteTable The **RouteTable** schema is used to configure health checks for Azure Route Tables. -| Sub-Schema | Setting | Default | Description | Highlight | -|-------------------|--------------|---------|--------------------------------------------------------|---------------------------------------------------------------------------------------------| +| Sub-Schema | Setting | Default | Description | Highlight | +|-------------------|--------------|---------|--------------------------------------------------------|-------------------------------------------------------------------------------------------| | ProvisioningState | true / false | true | Highlights Route Tables in a failed provisioning state | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) Provisioning is in a critical state | #### SiteRecovery -The **SiteRecovery** schema is used to configure health checks for Azure Site Recovery. +The **SiteRecovery** schema is used to configure health checks for Azure Site Recovery protected items. -| Sub-Schema | Setting | Default | Description | Highlight | -|-------------------|--------------|---------|-----------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------| -| ReplicationHealth | true / false | true | Highlights replicated items which are in a critical state | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) Replication health is in a critical state | -| FailoverHealth | true / false | true | Highlights the failover health status of replicated items | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) A successful test failover has not been performed on the replicated item | +| Sub-Schema | Setting | Default | Description | Highlight | +|-------------------|--------------|---------|------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------| +| ReplicationHealth | true / false | true | Highlights replicated items which are in a critical replication health state | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) Replication health is in a critical state | +| FailoverHealth | true / false | true | Highlights replicated items where the last test failover has failed | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) Test failover has failed | +| NoTestFailover | true / false | true | Highlights replicated items where no test failover has ever been performed | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) No test failover has been performed on the replicated item | #### StorageAccount The **StorageAccount** schema is used to configure health checks for Azure Storage Account. -| Sub-Schema | Setting | Default | Description | Highlight | -|-------------------------|--------------|---------|---------------------------------------------------------------------------|----------------------------------------------------------------------------------------------| +| Sub-Schema | Setting | Default | Description | Highlight | +|-------------------------|--------------|---------|---------------------------------------------------------------------------|--------------------------------------------------------------------------------------------| | ProvisioningState | true / false | true | Highlights storage accounts which are in a critical state | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) Provisioning is in a critical state | | StorageAccountKeyAccess | true / false | true | Highlights storage accounts which have storage account key access enabled | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) Storage account key access is enabled | | SecureTransfer | true / false | true | Highlights storage accounts which do not have secure transfer enabled | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) Secure transfer is disabled | @@ -465,21 +610,36 @@ The **StorageAccount** schema is used to configure health checks for Azure Stora #### VirtualMachine The **VirtualMachine** schema is used to configure health checks for Azure Virtual Machines. -| Sub-Schema | Setting | Default | Description | Highlight | -|-----------------|--------------|---------|-----------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Status | true / false | true | Highlights VMs which are not in a running state | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) VM is in a deallocated state | -| DiskEncryption | true / false | true | Highlights VMs which do not have disk encryption enabled | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) Disk encryption is disabled | +| Sub-Schema | Setting | Default | Description | Highlight | +|-----------------|--------------|---------|-----------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Status | true / false | true | Highlights VMs which are not in a running state | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) VM is in a deallocated state | +| DiskEncryption | true / false | true | Highlights VMs which do not have disk encryption enabled | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) Disk encryption is disabled | | BootDiagnostics | true / false | true | Highlights VMs which do not have boot diagnostics enabled with a custom storage account | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) Boot diagnostics is disabled
![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) Boot diagnostics is enabled with a managed storage account | -| BackupEnabled | true / false | true | Highlights VMs which do not have Azure Backup enabled | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) Backup is disabled | +| BackupEnabled | true / false | true | Highlights VMs which do not have Azure Backup enabled | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) Backup is disabled | #### VirtualNetwork The **VirtualNetwork** schema is used to configure health checks for Azure Virtual Networks. -| Sub-Schema | Setting | Default | Description | Highlight | -|-------------------|--------------|---------|--------------------------------------------------------------|---------------------------------------------------------------------------------------------| +| Sub-Schema | Setting | Default | Description | Highlight | +|-------------------|--------------|---------|--------------------------------------------------------------|-------------------------------------------------------------------------------------------| | ProvisioningState | true / false | true | Highlights Virtual Networks in a failed provisioning state | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) Provisioning is in a critical state | | DnsServers | true / false | true | Highlights Virtual Networks using default Azure-provided DNS | ![Info](https://placehold.co/15x15/D4E4F7/D4E4F7) Using default Azure-provided DNS | +#### VirtualNetworkGateway +The **VirtualNetworkGateway** schema is used to configure health checks for Azure Virtual Network Gateways. + +| Sub-Schema | Setting | Default | Description | Highlight | +|-------------------|--------------|---------|--------------------------------------------------------------------|-------------------------------------------------------------------------------------------| +| ProvisioningState | true / false | true | Highlights Virtual Network Gateways in a failed provisioning state | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) Provisioning is in a critical state | +| ConnectionStatus | true / false | true | Highlights VPN connections that are not Connected (InfoLevel 2+) | ![Warning](https://placehold.co/15x15/FFF4C7/FFF4C7) Connection is not in Connected state | + +#### VmScaleSet +The **VmScaleSet** schema is used to configure health checks for Azure Virtual Machine Scale Sets. + +| Sub-Schema | Setting | Default | Description | Highlight | +|-------------------|--------------|---------|---------------------------------------------------------|-------------------------------------------------------------------------------------------| +| ProvisioningState | true / false | true | Highlights VM Scale Sets in a failed provisioning state | ![Critical](https://placehold.co/15x15/FEDDD7/FEDDD7) Provisioning is in a critical state | + ## :computer: Examples diff --git a/Tests/AsBuiltReport.Microsoft.Azure.Tests.ps1 b/Tests/AsBuiltReport.Microsoft.Azure.Tests.ps1 index ec8de33..6bf9775 100644 --- a/Tests/AsBuiltReport.Microsoft.Azure.Tests.ps1 +++ b/Tests/AsBuiltReport.Microsoft.Azure.Tests.ps1 @@ -48,9 +48,9 @@ Describe 'AsBuiltReport.Microsoft.Azure Module Tests' { $Manifest.RequiredModules.Name | Should -Contain 'AsBuiltReport.Core' } - It 'Should require AsBuiltReport.Core version 1.6.1 or higher' { + It 'Should require AsBuiltReport.Core version 1.6.2 or higher' { $CoreModule = $Manifest.RequiredModules | Where-Object { $_.Name -eq 'AsBuiltReport.Core' } - $CoreModule.Version | Should -BeGreaterOrEqual ([Version]'1.6.1') + $CoreModule.Version | Should -BeGreaterOrEqual ([Version]'1.6.2') } It 'Should declare Az as an external module dependency' { @@ -58,10 +58,6 @@ Describe 'AsBuiltReport.Microsoft.Azure Module Tests' { $Manifest.PrivateData.PSData.ExternalModuleDependencies | Should -Contain 'Az' } - It 'Should declare AsBuiltReport.Core as an external module dependency' { - $Manifest.PrivateData.PSData.ExternalModuleDependencies | Should -Contain 'AsBuiltReport.Core' - } - It 'Should export the Invoke-AsBuiltReport.Microsoft.Azure function' { $Manifest.ExportedFunctions.Keys | Should -Contain 'Invoke-AsBuiltReport.Microsoft.Azure' } @@ -107,10 +103,7 @@ Describe 'AsBuiltReport.Microsoft.Azure Module Tests' { $Manifest.PrivateData.PSData.ReleaseNotes | Should -Match '^https?://' } - It 'Should have an IconUri' { - $Manifest.PrivateData.PSData.IconUri | Should -Not -BeNullOrEmpty - $Manifest.PrivateData.PSData.IconUri | Should -Match '^https?://' - } + It 'Should have module version matching expected format' { $Manifest.Version.ToString() | Should -Match '^\d+\.\d+\.\d+$' @@ -172,7 +165,7 @@ Describe 'AsBuiltReport.Microsoft.Azure Module Tests' { It 'Should have at least one private function' { $PrivatePath = Join-Path -Path $PSScriptRoot -ChildPath '..\AsBuiltReport.Microsoft.Azure\Src\Private' - $PrivateFunctions = Get-ChildItem -Path $PrivatePath -Filter '*.ps1' -ErrorAction SilentlyContinue + $PrivateFunctions = Get-ChildItem -Path $PrivatePath -Filter '*.ps1' -Recurse -ErrorAction SilentlyContinue $PrivateFunctions.Count | Should -BeGreaterThan 0 } } @@ -264,7 +257,8 @@ Describe 'AsBuiltReport.Microsoft.Azure Module Tests' { Context 'Private Functions' { BeforeAll { $PrivatePath = Join-Path -Path $PSScriptRoot -ChildPath '..\AsBuiltReport.Microsoft.Azure\Src\Private' - $PrivateFunctions = Get-ChildItem -Path $PrivatePath -Filter '*.ps1' -ErrorAction SilentlyContinue + $PrivateFunctions = Get-ChildItem -Path $PrivatePath -Filter '*.ps1' -Recurse -ErrorAction SilentlyContinue + $AllPrivateFunctions = $PrivateFunctions } It 'Should have Get-AbrAzStorageAccount function' { @@ -359,6 +353,30 @@ Describe 'AsBuiltReport.Microsoft.Azure Module Tests' { $PrivateFunctions.Name | Should -Contain 'Get-AbrAsrProtectedItems.ps1' } + It 'Should have Get-AbrAzAsrPolicy function' { + $PrivateFunctions.Name | Should -Contain 'Get-AbrAzAsrPolicy.ps1' + } + + It 'Should have Get-AbrAzAsrRecoveryPlan function' { + $PrivateFunctions.Name | Should -Contain 'Get-AbrAzAsrRecoveryPlan.ps1' + } + + It 'Should have Get-AbrAzAsrNetworkMapping function' { + $PrivateFunctions.Name | Should -Contain 'Get-AbrAzAsrNetworkMapping.ps1' + } + + It 'Should have Get-AbrAzUserAssignedManagedIdentity function' { + $PrivateFunctions.Name | Should -Contain 'Get-AbrAzUserAssignedManagedIdentity.ps1' + } + + It 'Should have Get-AbrAzAutomationAccount function' { + $PrivateFunctions.Name | Should -Contain 'Get-AbrAzAutomationAccount.ps1' + } + + It 'Should have Get-AbrAzDiagnosticSetting function' { + $PrivateFunctions.Name | Should -Contain 'Get-AbrAzDiagnosticSetting.ps1' + } + It 'Should have Get-CountryName function' { $PrivateFunctions.Name | Should -Contain 'Get-CountryName.ps1' } @@ -435,6 +453,64 @@ Describe 'AsBuiltReport.Microsoft.Azure Module Tests' { It 'Should have Get-AbrAzNetworkSecurityGroupRule helper function' { $PrivateFunctions.Name | Should -Contain 'Get-AbrAzNetworkSecurityGroupRule.ps1' } + + # Management Group + It 'Should have Get-AbrAzManagementGroup function' { + $PrivateFunctions.Name | Should -Contain 'Get-AbrAzManagementGroup.ps1' + } + + It 'Should have Get-AbrAzApplicationGateway function' { + $PrivateFunctions.Name | Should -Contain 'Get-AbrAzApplicationGateway.ps1' + } + + It 'Should have Get-AbrAzDataCollectionRule function' { + $PrivateFunctions.Name | Should -Contain 'Get-AbrAzDataCollectionRule.ps1' + } + + It 'Should have Get-AbrAzDdosProtectionPlan function' { + $PrivateFunctions.Name | Should -Contain 'Get-AbrAzDdosProtectionPlan.ps1' + } + + It 'Should have Get-AbrAzDesktopVirtualization function' { + $PrivateFunctions.Name | Should -Contain 'Get-AbrAzDesktopVirtualization.ps1' + } + + It 'Should have Get-AbrAzDnsForwardingRuleset function' { + $PrivateFunctions.Name | Should -Contain 'Get-AbrAzDnsForwardingRuleset.ps1' + } + + It 'Should have Get-AbrAzMaintenanceConfiguration function' { + $PrivateFunctions.Name | Should -Contain 'Get-AbrAzMaintenanceConfiguration.ps1' + } + + It 'Should have Get-AbrAzNetAppFiles function' { + $PrivateFunctions.Name | Should -Contain 'Get-AbrAzNetAppFiles.ps1' + } + + It 'Should have Get-AbrAzNetworkVirtualAppliance function' { + $PrivateFunctions.Name | Should -Contain 'Get-AbrAzNetworkVirtualAppliance.ps1' + } + + It 'Should have Get-AbrAzNetworkWatcher function' { + $PrivateFunctions.Name | Should -Contain 'Get-AbrAzNetworkWatcher.ps1' + } + + It 'Should have Get-AbrAzPrivateDnsZone function' { + $PrivateFunctions.Name | Should -Contain 'Get-AbrAzPrivateDnsZone.ps1' + } + + It 'Should have Get-AbrAzPublicIpAddress function' { + $PrivateFunctions.Name | Should -Contain 'Get-AbrAzPublicIpAddress.ps1' + } + + It 'Should have Get-AbrAzVirtualNetworkGateway function' { + $PrivateFunctions.Name | Should -Contain 'Get-AbrAzVirtualNetworkGateway.ps1' + } + + It 'Should have Get-AbrAzVmScaleSet function' { + $PrivateFunctions.Name | Should -Contain 'Get-AbrAzVmScaleSet.ps1' + } + } Context 'JSON Configuration' { @@ -465,11 +541,23 @@ Describe 'AsBuiltReport.Microsoft.Azure Module Tests' { } It 'SectionOrder should contain expected sections' { - $JsonConfig.Options.SectionOrder | Should -Contain 'StorageAccount' - $JsonConfig.Options.SectionOrder | Should -Contain 'VirtualMachine' - $JsonConfig.Options.SectionOrder | Should -Contain 'VirtualNetwork' - $JsonConfig.Options.SectionOrder | Should -Contain 'KeyVault' - $JsonConfig.Options.SectionOrder | Should -Contain 'LoadBalancer' + $ExpectedSections = @( + 'StorageAccount', 'VirtualMachine', 'VirtualNetwork', 'KeyVault', 'LoadBalancer', + 'UserAssignedManagedIdentity', 'AutomationAccount', 'DiagnosticSetting', + 'ApplicationGateway', 'AsrNetworkMapping', 'AsrPolicy', 'AsrRecoveryPlan', 'AvailabilitySet', + 'Bastion', 'DataCollectionRule', 'DdosProtectionPlan', 'DesktopVirtualization', 'DnsForwardingRuleset', + 'DnsPrivateResolver', 'ExpressRoute', 'Firewall', 'FirewallPolicy', 'IpGroup', 'LogAnalyticsWorkspace', + 'MaintenanceConfiguration', 'NetAppFiles', 'NetworkSecurityGroup', 'NetworkVirtualAppliance', + 'NetworkWatcher', 'Policy', 'PrivateDnsZone', 'PrivateEndpoint', 'PublicIpAddress', + 'RecoveryServicesVault', 'RouteTable', 'SiteRecovery', 'VirtualNetworkGateway', 'VmScaleSet' + ) + + $MissingSections = $ExpectedSections | Where-Object { $_ -notin $JsonConfig.Options.SectionOrder } + + if ($MissingSections.Count -gt 0) { + $ErrorMessage = "SectionOrder is missing expected section(s):`n" + ($MissingSections -join "`n") + $MissingSections.Count | Should -Be 0 -Because $ErrorMessage + } } It 'Should have an InfoLevel section' { @@ -566,10 +654,90 @@ Describe 'AsBuiltReport.Microsoft.Azure Module Tests' { $JsonConfig.InfoLevel.PSObject.Properties.Name | Should -Contain 'Tenant' } + It 'InfoLevel should include ManagementGroup' { + $JsonConfig.InfoLevel.PSObject.Properties.Name | Should -Contain 'ManagementGroup' + } + + It 'InfoLevel should include UserAssignedManagedIdentity' { + $JsonConfig.InfoLevel.PSObject.Properties.Name | Should -Contain 'UserAssignedManagedIdentity' + } + + It 'InfoLevel should include AutomationAccount' { + $JsonConfig.InfoLevel.PSObject.Properties.Name | Should -Contain 'AutomationAccount' + } + + It 'InfoLevel should include DiagnosticSetting' { + $JsonConfig.InfoLevel.PSObject.Properties.Name | Should -Contain 'DiagnosticSetting' + } + It 'InfoLevel should include VirtualNetwork' { $JsonConfig.InfoLevel.PSObject.Properties.Name | Should -Contain 'VirtualNetwork' } + It 'InfoLevel should include ApplicationGateway' { + $JsonConfig.InfoLevel.PSObject.Properties.Name | Should -Contain 'ApplicationGateway' + } + + It 'InfoLevel should include AsrNetworkMapping' { + $JsonConfig.InfoLevel.PSObject.Properties.Name | Should -Contain 'AsrNetworkMapping' + } + + It 'InfoLevel should include AsrPolicy' { + $JsonConfig.InfoLevel.PSObject.Properties.Name | Should -Contain 'AsrPolicy' + } + + It 'InfoLevel should include AsrRecoveryPlan' { + $JsonConfig.InfoLevel.PSObject.Properties.Name | Should -Contain 'AsrRecoveryPlan' + } + + It 'InfoLevel should include DataCollectionRule' { + $JsonConfig.InfoLevel.PSObject.Properties.Name | Should -Contain 'DataCollectionRule' + } + + It 'InfoLevel should include DdosProtectionPlan' { + $JsonConfig.InfoLevel.PSObject.Properties.Name | Should -Contain 'DdosProtectionPlan' + } + + It 'InfoLevel should include DesktopVirtualization' { + $JsonConfig.InfoLevel.PSObject.Properties.Name | Should -Contain 'DesktopVirtualization' + } + + It 'InfoLevel should include DnsForwardingRuleset' { + $JsonConfig.InfoLevel.PSObject.Properties.Name | Should -Contain 'DnsForwardingRuleset' + } + + It 'InfoLevel should include MaintenanceConfiguration' { + $JsonConfig.InfoLevel.PSObject.Properties.Name | Should -Contain 'MaintenanceConfiguration' + } + + It 'InfoLevel should include NetAppFiles' { + $JsonConfig.InfoLevel.PSObject.Properties.Name | Should -Contain 'NetAppFiles' + } + + It 'InfoLevel should include NetworkVirtualAppliance' { + $JsonConfig.InfoLevel.PSObject.Properties.Name | Should -Contain 'NetworkVirtualAppliance' + } + + It 'InfoLevel should include NetworkWatcher' { + $JsonConfig.InfoLevel.PSObject.Properties.Name | Should -Contain 'NetworkWatcher' + } + + It 'InfoLevel should include PrivateDnsZone' { + $JsonConfig.InfoLevel.PSObject.Properties.Name | Should -Contain 'PrivateDnsZone' + } + + It 'InfoLevel should include PublicIpAddress' { + $JsonConfig.InfoLevel.PSObject.Properties.Name | Should -Contain 'PublicIpAddress' + } + + It 'InfoLevel should include VirtualNetworkGateway' { + $JsonConfig.InfoLevel.PSObject.Properties.Name | Should -Contain 'VirtualNetworkGateway' + } + + It 'InfoLevel should include VmScaleSet' { + $JsonConfig.InfoLevel.PSObject.Properties.Name | Should -Contain 'VmScaleSet' + } + It 'HealthCheck should include Bastion checks' { $JsonConfig.HealthCheck.PSObject.Properties.Name | Should -Contain 'Bastion' } @@ -633,6 +801,74 @@ Describe 'AsBuiltReport.Microsoft.Azure Module Tests' { It 'HealthCheck should include VirtualNetwork checks' { $JsonConfig.HealthCheck.PSObject.Properties.Name | Should -Contain 'VirtualNetwork' } + + It 'HealthCheck should include AutomationAccount checks' { + $JsonConfig.HealthCheck.PSObject.Properties.Name | Should -Contain 'AutomationAccount' + } + + It 'HealthCheck should include DiagnosticSetting checks' { + $JsonConfig.HealthCheck.PSObject.Properties.Name | Should -Contain 'DiagnosticSetting' + } + + It 'HealthCheck should include ApplicationGateway checks' { + $JsonConfig.HealthCheck.PSObject.Properties.Name | Should -Contain 'ApplicationGateway' + } + + It 'HealthCheck should include AsrNetworkMapping checks' { + $JsonConfig.HealthCheck.PSObject.Properties.Name | Should -Contain 'AsrNetworkMapping' + } + + It 'HealthCheck should include AsrPolicy checks' { + $JsonConfig.HealthCheck.PSObject.Properties.Name | Should -Contain 'AsrPolicy' + } + + It 'HealthCheck should include DataCollectionRule checks' { + $JsonConfig.HealthCheck.PSObject.Properties.Name | Should -Contain 'DataCollectionRule' + } + + It 'HealthCheck should include DdosProtectionPlan checks' { + $JsonConfig.HealthCheck.PSObject.Properties.Name | Should -Contain 'DdosProtectionPlan' + } + + It 'HealthCheck should include DesktopVirtualization checks' { + $JsonConfig.HealthCheck.PSObject.Properties.Name | Should -Contain 'DesktopVirtualization' + } + + It 'HealthCheck should include DnsForwardingRuleset checks' { + $JsonConfig.HealthCheck.PSObject.Properties.Name | Should -Contain 'DnsForwardingRuleset' + } + + It 'HealthCheck should include NetAppFiles checks' { + $JsonConfig.HealthCheck.PSObject.Properties.Name | Should -Contain 'NetAppFiles' + } + + It 'HealthCheck should include NetworkVirtualAppliance checks' { + $JsonConfig.HealthCheck.PSObject.Properties.Name | Should -Contain 'NetworkVirtualAppliance' + } + + It 'HealthCheck should include NetworkWatcher checks' { + $JsonConfig.HealthCheck.PSObject.Properties.Name | Should -Contain 'NetworkWatcher' + } + + It 'HealthCheck should include PrivateDnsZone checks' { + $JsonConfig.HealthCheck.PSObject.Properties.Name | Should -Contain 'PrivateDnsZone' + } + + It 'HealthCheck should include PublicIpAddress checks' { + $JsonConfig.HealthCheck.PSObject.Properties.Name | Should -Contain 'PublicIpAddress' + } + + It 'HealthCheck should include SiteRecovery checks' { + $JsonConfig.HealthCheck.PSObject.Properties.Name | Should -Contain 'SiteRecovery' + } + + It 'HealthCheck should include VirtualNetworkGateway checks' { + $JsonConfig.HealthCheck.PSObject.Properties.Name | Should -Contain 'VirtualNetworkGateway' + } + + It 'HealthCheck should include VmScaleSet checks' { + $JsonConfig.HealthCheck.PSObject.Properties.Name | Should -Contain 'VmScaleSet' + } } Context 'Configuration Schema Validation' { @@ -712,6 +948,10 @@ Describe 'AsBuiltReport.Microsoft.Azure Module Tests' { $JsonConfig.Options.ShowTags | Should -BeOfType [bool] } + It 'Options.EnableDiagrams should be boolean' { + $JsonConfig.Options.EnableDiagrams | Should -BeOfType [bool] + } + It 'Policy InfoLevel structure should have Assignments and Definitions' { $JsonConfig.InfoLevel.Policy.PSObject.Properties.Name | Should -Contain 'Assignments' $JsonConfig.InfoLevel.Policy.PSObject.Properties.Name | Should -Contain 'Definitions' @@ -771,7 +1011,7 @@ Describe 'Module File Syntax and Quality' { $LanguagePath = Join-Path -Path $PSScriptRoot -ChildPath '..\AsBuiltReport.Microsoft.Azure\Language\en-US' $LocalizedData = Import-LocalizedData -BaseDirectory $LanguagePath -FileName 'MicrosoftAzure.psd1' $ModuleRoot = Join-Path -Path $PSScriptRoot -ChildPath '..\AsBuiltReport.Microsoft.Azure' - $PrivateFunctions = Get-ChildItem -Path "$ModuleRoot\Src\Private" -Filter '*.ps1' -ErrorAction SilentlyContinue + $PrivateFunctions = Get-ChildItem -Path "$ModuleRoot\Src\Private" -Filter '*.ps1' -Recurse -ErrorAction SilentlyContinue } It 'Should have valid PowerShell localization data files' { @@ -905,6 +1145,7 @@ Describe 'Module File Syntax and Quality' { 'Get-AbrAzVirtualNetworkPeering', # VNet peering 'Get-AbrAzVirtualNetworkSubnet', # VNet subnet 'Get-AbrAsrProtectedItems', # Site Recovery items + 'Get-AbrAzAsr', # ASR sub-functions (policies, plans, mappings) 'Get-AbrAzPolicy' # Policy sub-functions ) @@ -976,38 +1217,6 @@ Describe 'Module File Syntax and Quality' { } } - # Verify new v0.2.0 functions have localization - It 'Should have GetAbrAzAvailabilitySet localization section' { - $LocalizedData.GetAbrAzAvailabilitySet | Should -Not -BeNullOrEmpty - } - - It 'Should have GetAbrAzBastion localization section' { - $LocalizedData.GetAbrAzBastion | Should -Not -BeNullOrEmpty - } - - It 'Should have GetAbrAzFirewallPolicy localization section' { - $LocalizedData.GetAbrAzFirewallPolicy | Should -Not -BeNullOrEmpty - } - - It 'Should have GetAbrAzPrivateEndpoint localization section' { - $LocalizedData.GetAbrAzPrivateEndpoint | Should -Not -BeNullOrEmpty - } - - It 'Should have GetAbrAzDnsPrivateResolver localization section' { - $LocalizedData.GetAbrAzDnsPrivateResolver | Should -Not -BeNullOrEmpty - } - - It 'Should have GetAbrAzExpressRouteCircuit localization section' { - $LocalizedData.GetAbrAzExpressRouteCircuit | Should -Not -BeNullOrEmpty - } - - It 'Should have GetAbrAzIpGroup localization section' { - $LocalizedData.GetAbrAzIpGroup | Should -Not -BeNullOrEmpty - } - - It 'Should have GetAbrAzRouteTable localization section' { - $LocalizedData.GetAbrAzRouteTable | Should -Not -BeNullOrEmpty - } } Context 'Code Style and Standards' {