MyPSFunctions.Az.ps1

<#
    ===========================================================================
     Created with: SAPIEN Technologies, Inc., PowerShell Studio 2021 v5.8.196
     Created on: 10/26/2023 7:57 PM
     Created by: John@MyPSFunctions.com
     Organization: MyPSFunctions
     Filename: MyPSFunctions.Az.psm1
    -------------------------------------------------------------------------
     Module Name: MyPSFunctions.Az
    ===========================================================================
#>

#region Basics
####################################################
############################## Basics ################
####################################################
Function Write-AzureLog
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$Level,
        [Parameter(Mandatory = $false,
                   Position = 2)]
        [string]$LogPath,
        [Parameter(Mandatory = $true,
                   Position = 3)]
        [string]$Message
    )
    
    switch ($Level)
    {
        Warning
        {
            # Write warning log
            if ($LogPath) { Write-Output "[$(Get-Date -Format "yyyy-MM-dd HH:mm:ss")] WARNING: $Message" | Out-File -FilePath $LogPath -Append }
            Write-Output "[$(Get-Date -Format "yyyy-MM-dd HH:mm:ss")] WARNING: $Message"
        }
        Error
        {
            # Write Error log
            if ($LogPath) { Write-Output "[$(Get-Date -Format "yyyy-MM-dd HH:mm:ss")] Error: $Message" | Out-File -FilePath $LogPath -Append }
            Write-Output "[$(Get-Date -Format "yyyy-MM-dd HH:mm:ss")] Error: $Message"
        }
        default
        {
            # Write Information log
            if ($LogPath) { Write-Output "[$(Get-Date -Format "yyyy-MM-dd HH:mm:ss")] INFO: $Message" | Out-File -FilePath $LogPath -Append }
            Write-Output "[$(Get-Date -Format "yyyy-MM-dd HH:mm:ss")] INFO: $Message"
        }
    }
}

#endregion

#region Azure
####################################################
############################## Azure ################
####################################################
Function Switch-AzSubscription
{
    [CmdletBinding()]
    param ()
    
    $AzContext = Get-AzContext
    $AzAccount = $AzContext.Account.ID
    $AzSubs = Get-AzSubscription
    $SelectedSub = $AzSubs | Select Name, State, Id | Out-GridView -PassThru -Title 'Select One Subscription, then click on OK to validate your selection'
    $SelectedSub_Id = $SelectedSub.Id
    $SelectedSub_Name = $SelectedSub.Name
    Set-AzContext -Subscription $SelectedSub_Id
    Write-Log Warning -Message "Switch to subscription: $SelectedSub_Name ($SelectedSub_Id)"
    $Host.UI.RawUI.WindowTitle = "$AzAccount connected to Sub: $SelectedSub_Name"
}

Function Connect-Az
{
    param
    (
        [Parameter(Position = 1)]
        [string]$AlternateID
    )
    If ($AlternateID)
    {
        $MyPSFunctionsAzAdmin = $AlternateID
    }
    Write-Host -ForegroundColor Yellow "Please validate the Az Modules are installed"
    # Connect to Azure AD
    Try
    {
        Connect-AzAccount -AccountID $MyPSFunctionsAzAdmin
        $AzContext = Get-AzContext
        $AzAccount = $AzContext.Account.ID
        $AzSubs = Get-AzSubscription
        $SelectedSub = $AzSubs | Select Name, State, Id | Out-GridView -PassThru -Title 'Select One Subscription, then click on OK to validate your selection' -outp
        $SelectedSub_Id = $SelectedSub.Id
        $SelectedSub_Name = $SelectedSub.Name
        Set-AzContext -Subscription $SelectedSub_Id
        Write-Log Warning -Message "Switch to subscription: $SelectedSub_Name ($SelectedSub_Id)"
        $Host.UI.RawUI.WindowTitle = "$AzAccount connected to Sub: $SelectedSub_Name"
    }
    Catch
    {
    $ErrorMessage = $Error[0].Exception.Message
    $CMDLet = $Error[0].InvocationInfo.Line
    $FailedItem = $Error[0].Exception.ItemName
    Write-Log Error -Message "Failed to run the following CMDLet: $CMDLet"
    Write-Log Error -Message "Failed with Error:$ErrorMessage"    
        
    }
}



Function Get-AzToken
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$TenantID,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$AppID,
        [Parameter(Mandatory = $true,
                   Position = 3)]
        [string]$AppSecret
    )
    
    # Construct URI and body needed for authentication
    $URI = "https://login.microsoftonline.com/$tenantId/oauth2/token?api-version=2020-06-01"
    $Body = @{
        Grant_Type    = "client_credentials"
        resource      = "https://management.core.windows.net/"
        Client_Id      = $AppID
        Client_Secret = $AppSecret
    }
    # Get OAuth 2.0 Token
    $connection = Invoke-RestMethod -Uri $URI -Method POST -Body $body
    # Unpack Access Token
    $Token = $connection.access_token
    Return $Token
}

Function Create-AzArcLicense
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$Subscription,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$ResourceGroupName,
        [Parameter(Mandatory = $true,
                   Position = 3)]
        [String]$TenantId,
        [Parameter(Mandatory = $true,
                   Position = 4)]
        [String]$ApplicationId,
        [Parameter(Mandatory = $true,
                   Position = 5)]
        [String]$Secret,
        [Parameter(Mandatory = $true,
                   Position = 6)]
        [String]$LicenseName
    )
    
    $Token = Get-AzToken -TenantID $TenantId -AppID $ApplicationId -AppSecret $Secret
    $body = @{
        "location"   = "Canada Central"
        "properties" = @{
            "licenseDetails" = @{
                "state"         = "Activated"
                "target"     = "Windows Server 2012"
                "Edition"    = "Datacenter"
                "Type"         = "vCore"
                "Processors" = 8
            }
        }
    }
    $URI = "https://management.azure.com/subscriptions/" + $SubscriptionId + "/resourceGroups/" + $RGName + "/providers/Microsoft.HybridCompute/licenses/" + $LicenseName + "?api-version=2023-06-20-preview"
    $param_NewResourceGroup = @{
        Uri            = $URI
        ContentType = "application/json"
        Method        = 'PUT'
        headers        = @{
            authorization = "Bearer $Token"
            host          = 'management.azure.com'
        }
        body        = ($Body | ConvertTo-Json)
    }
    Invoke-RestMethod @param_NewResourceGroup
    
}

Function Backup-AzFirewallPolicies
{
    [CmdletBinding()]
    param ()
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $AzContext = Get-AzContext
    $CurrentSubscriptionName = $AzContext.Subscription.Name
    
    #Azure Firewall Policies
    $AzResourcesFirewallPolicies = Get-AzResource | where { $_.ResourceType -eq "Microsoft.Network/firewallPolicies" }
    $SelectedAzFirewallPolicy = $AzResourcesFirewallPolicies | Select Name, ResourceGroupName, Location | Out-GridView -PassThru
    $SelectedAzFirewallPolicyName = $SelectedAzFirewallPolicy.Name
    $SelectedAzFirewallPolicyResourceGroupName = $SelectedAzFirewallPolicy.ResourceGroupName
    $AzFirewallPolicy = Get-AzFirewallPolicy -Name $SelectedAzFirewallPolicyName -ResourceGroupName $SelectedAzFirewallPolicyResourceGroupName
    $AzFirewallPolicyName = $AzFirewallPolicy.Name
    $AzFirewallPolicy_RuleCollectionGroups = $AzFirewallPolicy.RuleCollectionGroups
    $DateFull1 = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $AzFwPolicyXMLFile = "Backup_" + $AzFirewallPolicyName + "_" + $DateFull1 + ".xml"
    $AzFwPolicyXMLFile | Export-Clixml $AzFwPolicyXMLFile
    $AzFirewallPolicyRuleCollectionGroup = $Null
    $AzFirewallPolicyRuleCollectionGroup = @()
    
    $Table = $Null
    $Table = @()
    
    foreach ($AzFirewallPolicy_RuleCollectionGroup in $AzFirewallPolicy_RuleCollectionGroups)
    {
        $AzFirewallPolicy_RuleCollectionGroup_Name = $Null
        $AzFirewallPolicy_RuleCollectionGroupID = $Null
        $AzFirewallPolicy_RuleCollectionGroupID = $AzFirewallPolicy_RuleCollectionGroup.ID
        $AzFirewallPolicy_RuleCollectionGroup_Name = $AzFirewallPolicy_RuleCollectionGroupID.Substring($AzFirewallPolicy_RuleCollectionGroupID.LastIndexOf("/") + 1)
        $AzFirewallPolicyRuleCollectionGroup = Get-AzFirewallPolicyRuleCollectionGroup -AzureFirewallPolicyName $SelectedAzFirewallPolicyName -Name $AzFirewallPolicy_RuleCollectionGroup_Name -ResourceGroupName $SelectedAzFirewallPolicyResourceGroupName
        $AzFirewallPolicyRuleCollectionGroup_Properties = $AzFirewallPolicyRuleCollectionGroup.Properties.RuleCollection
        $DateFull2 = Get-Date -Format "ddMMyyyy_HH-mm-ss"
        $AzFwPolicyRuleCollectionGroupXMLFile = "Backup_" + $AzFirewallPolicy_RuleCollectionGroup_Name + "_" + $DateFull2 + ".xml"
        $AzFirewallPolicyRuleCollectionGroup_Properties  | Export-Clixml $AzFwPolicyRuleCollectionGroupXMLFile
        $RCGCount = ($AzFirewallPolicyRuleCollectionGroup_Properties | Measure).count
        [Int]$i = 1
        foreach ($AzFirewallPolicyRuleCollectionGroup_Property  in $AzFirewallPolicyRuleCollectionGroup_Properties)
        {
            $AzFirewallPolicyRuleCollectionGroup_Property_Name = $Null
            $AzFirewallPolicyRuleCollectionGroup_Property_Priority = $Null
            $AzFirewallPolicyRuleCollectionGroup_Property_rules = $Null
            $AzFirewallPolicyRuleCollectionGroup_Property_Name = $AzFirewallPolicyRuleCollectionGroup_Property.Name
            $AzFirewallPolicyRuleCollectionGroup_Property_Priority = $AzFirewallPolicyRuleCollectionGroup_Property.Priority
            $AzFirewallPolicyRuleCollectionGroup_Property_rules = $AzFirewallPolicyRuleCollectionGroup_Property.rules
            Write-Log Warning -Message "Analysing Rule Collection Group: $AzFirewallPolicyRuleCollectionGroup_Property_Name --- $i/$RCGCount"
            $RulesCount = ($AzFirewallPolicyRuleCollectionGroup_Property_rules | Measure).count
            [Int]$ii = 1
            foreach ($AzFirewallPolicyRuleCollectionGroup_Property_rule in $AzFirewallPolicyRuleCollectionGroup_Property_rules)
            {
                $RuleName = $Null
                $RuleType = $Null
                $Protocols = $Null
                $SourcesAddresses = $Null
                $SourceIPGroups = $Null
                $DestinationAddresses = $Null
                $DestinationIPGroups = $Null
                $DestionationPorts = $Null
                $TargetFqdns = $Null
                
                $RuleName = $AzFirewallPolicyRuleCollectionGroup_Property_rule.Name
                Write-Log Warning -Message "Analysing Rule: $RuleName --- $ii/$RulesCount"
                [string]$RuleType = $AzFirewallPolicyRuleCollectionGroup_Property_rule.RuleType
                If ($RuleType -eq "ApplicationRule") { $Protocols = $AzFirewallPolicyRuleCollectionGroup_Property_rule.Protocols.port -join "-" }
                else { [string]$Protocols = $AzFirewallPolicyRuleCollectionGroup_Property_rule.Protocols }
                [string]$SourceAddresses = $AzFirewallPolicyRuleCollectionGroup_Property_rule.SourceAddresses
                [string]$SourceIPGroups = $AzFirewallPolicyRuleCollectionGroup_Property_rule.SourceIPGroups
                [string]$DestinationAddresses = $AzFirewallPolicyRuleCollectionGroup_Property_rule.DestinationAddresses
                [string]$DestinationFqdns = $AzFirewallPolicyRuleCollectionGroup_Property_rule.DestinationFqdns
                [string]$DestinationIPGroups = $AzFirewallPolicyRuleCollectionGroup_Property_rule.DestinationIPGroups
                [string]$DestionationPorts = $AzFirewallPolicyRuleCollectionGroup_Property_rule.DestinationPorts
                [string]$TargetFqdns = $AzFirewallPolicyRuleCollectionGroup_Property_rule.TargetFqdns
                
                
                $Table += New-object PSobject -Property ([Ordered] @{
                        AzFirewallPolicyName          = $SelectedAzFirewallPolicyName;
                        ResourceGroup                  = $SelectedAzFirewallPolicyResourceGroupName;
                        AzFirewallCollectionGroupName = $AzFirewallPolicy_RuleCollectionGroup_Name;
                        RuleCollectionGroupName          = $AzFirewallPolicyRuleCollectionGroup_Property_Name;
                        RuleCollectionGroupPriority   = $AzFirewallPolicyRuleCollectionGroup_Property_Priority;
                        RuleName                      = $RuleName;
                        RuleType                      = $RuleType;
                        Protocols                      = $Protocols;
                        SourcesAddresses              = $SourceAddresses;
                        SourceIPGroups                  = $SourceIPGroups;
                        TargetFqdns                      = $TargetFqdns;
                        DestinationAddresses          = $DestinationAddresses;
                        DestinationFqdns              = $DestinationFqdns;
                        DestinationIPGroups              = $DestinationIPGroups;
                        DestionationPorts              = $DestionationPorts;
                    })
                $ii++

            }
            $i++
        }
        
    }
    
    
    $ReportFile = ".\Report_AzFirewall_Policy_" + $CurrentSubscriptionName + "_" + $SelectedAzFirewallPolicyName + "_" + $DateFull + ".csv"
    $ReportFilexlsx = ".\Report_AzFirewall_Policy_" + $CurrentSubscriptionName + "_" + $SelectedAzFirewallPolicyName + "_" + $DateFull + ".xlsx"
    $Table | Export-Csv $ReportFile -NoTypeInformation -Encoding UTF8
    $Table | Export-Excel $ReportFilexlsx -TableName "AzFirewallRules" -Title "AzFirewall Rules" -TitleBold -WorksheetName "AzFirewallRules" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFile"
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
}

Function Generate-AzRoleAssignmentsReportForAllSubscriptions
{
    [CmdletBinding()]
    param ()
    
    # Report for Permission as Subscription level
    Try
    {
        Write-Log warning -Message "The script is retreiving all the AzSubscriptions"
        $AzSubs = Get-AzSubscription
        $AzSubsCount = ($AzSubs | Measure).count
        Write-Log Info -Message "The script found $AzSubsCount AzSubscriptions"
        
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log Error -Message "Failed to found all AzSubscriptions"
        Write-Log Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log Error -Message "Failed with Error:$ErrorMessage"
    }
    [Int]$i = 1
    $Table = $Null
    $Table = @()
    ForEach ($AzSub in $AzSubs)
    {
        $AzSubName = $Null
        $AzSubName = $AzSub.name
        Write-log Warning -message "The script is analyzing the Subscription: $Name ….. --- $i/$AzSubsCount"
        
        
        # Get Role Assignment at the Subsciption Level
        Try
        {
            Write-Log warning -Message "The script is retreiving all Role Assignments at the Subscription level"
            $AzSubscriptionRoleAssignements = Get-AzRoleAssignment # DisplayName, RoleDefinitionName, ObjectType, Scope
            $AzSubscriptionRoleAssignementsCount = ($AzSubscriptionRoleAssignements | Measure).count
            Write-Log Info -Message "All Role Assignments at the Subscription level are retrieved ( $AzSubscriptionRoleAssignementsCount)"
        }
        Catch
        {
            $ErrorMessage = $Error[0].Exception.Message
            $CMDLet = $Error[0].InvocationInfo.Line
            $FailedItem = $Error[0].Exception.ItemName
            Write-Log Error -Message "Failed to retreive all Role Assignments at the Subscription level"
            Write-Log Error -Message "Failed to run the following CMDLet: $CMDLet"
            Write-Log Error -Message "Failed with Error:$ErrorMessage"
        }
        
        #Initiate the Hash Table
        [Int]$ii = 1
        
        ForEach ($AzSubscriptionRoleAssignement in $AzSubscriptionRoleAssignements)
        {
            
            $AzSubscriptionRoleAssignementDisplayName = $Null
            $AzSubscriptionRoleAssignementRoleDefinitionName = $Null
            $AzSubscriptionRoleAssignementObjectType = $Null
            $AzSubscriptionRoleAssignementScope = $Null
            $AzSubscriptionRoleAssignementDisplayName = $AzSubscriptionRoleAssignement.DisplayName
            $AzSubscriptionRoleAssignementRoleDefinitionName = $AzSubscriptionRoleAssignement.RoleDefinitionName
            $AzSubscriptionRoleAssignementObjectType = $AzSubscriptionRoleAssignement.ObjectType
            $AzSubscriptionRoleAssignementScope = $AzSubscriptionRoleAssignement.Scope
            
            Write-log Warning -message "The script is analyzing $AzSubscriptionRoleAssignementDisplayName ….. --- $ii/$AzSubscriptionRoleAssignementsCount"
            
            $Table += New-object PSobject -Property ([Ordered] @{
                    AzSubName           = $AzSubName;
                    DisplayName           = $AzSubscriptionRoleAssignementDisplayName;
                    RoleDefinitionName = $AzSubscriptionRoleAssignementRoleDefinitionName;
                    ObjectType           = $AzSubscriptionRoleAssignementObjectType;
                    Scope               = $AzSubscriptionRoleAssignementScope;
                })
            
            $ii++
        }
        $i++
    }
    
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = ".\Report_All_AzSubscriptions_RoleAssignments_ " + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFilexlsx -TableName "AzSubscriptionsRoleAssignments" -Title "AzSubscriptions Role Assignments" -TitleBold -WorksheetName "AzSubscriptionsRoleAssignments" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
    
}

Function Generate-AzRoleAssignmentsReportForAllSubscriptionsOld
{
    
    Try
    {
        Write-Log Info -Message "The script is collecting all Subscriptions information"
        $AzSubscriptions = Get-AzSubscription -TenantId (Get-AzContext).Tenant
        $AzSubscriptionCount = ($AzSubscriptions | Measure).count
        Write-CLog warning -Message "The script find $AzSubscriptionCount subscriptions"
        #Initiate the Hash Table
        [Int]$i = 1
        $Table = $Null
        $Table = @()
        
        ForEach ($AzSubscription in $AzSubscriptions)
        {
            $AzSubscriptionName = $Null
            $AzSubscriptionName = $AzSubscription.name
            $AzSubscriptionID = $Null
            $AzSubscriptionID = $AzSubscription.Id
            $AzSubscriptionState = $Null
            $AzSubscriptionState = $AzSubscription.State
            Write-CLog warning -message "The script is analyzing $AzSubscriptionName ….. --- $i/$AzSubscriptionCount"
            
            Select-AzSubscription -Subscription $AzSubscriptionName
            $AzResources = $Null
            $AzResources = Get-AzResourceGroup
            $AzResourcesCount = ($AzResources | Measure).count
            Write-Log warning -Message "The script find $AzResourcesCount Resource Groups"
            [Int]$ii = 1
            Foreach ($AzResource in $AzResources)
            {
                
                $ResourceGroupName = $AzResource.ResourceGroupName
                $Location = $Null
                $Location = $AzResource.Location
                Write-Log warning -Message "The script is analyzing the following Resource Group: $ResourceGroupName --- $ii/$AzResourcesCount"
                $AzRoleAssignments = Get-AzRoleAssignment -ResourceGroupName $ResourceGroupName
                $AzRoleAssignmentsCount = ($AzRoleAssignments | Measure).count
                [Int]$iii = 1
                Foreach ($AzRoleAssignment in $AzRoleAssignments)
                {
                    $DisplayName = $Null
                    $DisplayName = $AzRoleAssignment.DisplayName
                    $SignInName = $Null
                    $SignInName = $AzRoleAssignment.SignInName
                    $RoleDefinitionName = $Null
                    $RoleDefinitionName = $AzRoleAssignment.RoleDefinitionName
                    $ObjectType = $Null
                    $ObjectType = $AzRoleAssignment.ObjectType
                    Write-Log Info -Message "The script is analyzing the following Role Assignment: $DisplayName --- $iii/$AzRoleAssignmentsCount"
                    $Table += New-object PSobject -Property ([Ordered] @{
                            AzSubscriptionName  = $AzSubscriptionName;
                            AzSubscriptionID    = $AzSubscriptionID;
                            AzSubscriptionState = $AzSubscriptionState;
                            ResourceGroupName   = $ResourceGroupName;
                            Location            = $Location;
                            DisplayName            = $DisplayName;
                            SignInName            = $SignInName;
                            RoleDefinitionName  = $RoleDefinitionName;
                            ObjectType            = $ObjectType;
                        })
                    $iii++
                }
                $ii++
            }
            
            $i++
        }
        
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log Error -Message "Failed to run $CMDLet"
        Write-Log Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log Error -Message "Failed with Error:$ErrorMessage"
        $Status = "Failed"
    }
    
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = ".\Report_AzSubscriptionsPermissions_" + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFilexlsx -TableName "AzSubscriptionPermissions" -Title "AzSubscriptionPermissions" -TitleBold -WorksheetName "AzSubscriptionPermissions" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
}

Function Generate-AzNSGForAllSubscriptions
{
    [CmdletBinding()]
    param ()
    
    # Report for Permission as Subscription level
    Try
    {
        Write-Log warning -Message "The script is retreiving all the AzSubscriptions"
        $AzSubs = Get-AzSubscription
        $AzSubsCount = ($AzSubs | Measure).count
        Write-Log Info -Message "The script found $AzSubsCount AzSubscriptions"
        
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log Error -Message "Failed to found all AzSubscriptions"
        Write-Log Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log Error -Message "Failed with Error:$ErrorMessage"
    }
    [Int]$i = 1
    $Table = $Null
    $Table = @()
    
    ForEach ($AzSub in $AzSubs)
    {
        $AzSubName = $Null
        $AzSubName = $AzSub.name
        $AzSubId = $Null
        $AzSubId = $AzSub.Id
        
        
        # Get Role Assignment at the Subsciption Level
        Try
        {
            Write-log Warning -message "The script is analyzing the Subscription: $Name ….. --- $i/$AzSubsCount"
            Select-AzSubscription -SubscriptionId $AzSubId
            $NSGs = Get-AzNetworkSecurityGroup
            $NSGsCount = ($NSGs | Measure).count
            Write-Log Info -Message "The Script found NSGs: $NSGsCount"
        }
        Catch
        {
            $ErrorMessage = $Error[0].Exception.Message
            $CMDLet = $Error[0].InvocationInfo.Line
            $FailedItem = $Error[0].Exception.ItemName
            Write-Log Error -Message "Failed to find NSGs"
            Write-Log Error -Message "Failed to run the following CMDLet: $CMDLet"
            Write-Log Error -Message "Failed with Error:$ErrorMessage"
        }
        
        #Initiate the Hash Table
        [Int]$ii = 1
        
        ForEach ($NSG in $NSGs)
        {
            $NSGRules = $Null
            $NSGName = $Null
            $NSGResourceGroupName = $Null
            
            
            $NSGRules = $NSG.SecurityRules
            $NSGName = $NSG.Name
            $NSGResourceGroupName = $NSG.ResourceGroupName
            Write-Log Warning -Message "The Script is analyzing the following NSGs: $NSGName --- $ii/$NSGsCount"
            [Int]$iii = 1
            $NSGRulesCount = ($NSGRules | Measure).count
            Write-Log Warning -Message "NSG Rules found: $NSGRulesCount"
            ForEach ($NSGRule in $NSGRules)
            {
                $NSGRuleName = $Null
                $NSGRuleProtocol = $Null
                $NSGRuleSourcePortRange = $Null
                $NSGRuleSourceAddressPrefix = $Null
                $NSGRuleSourceApplicationSecurityGroups = $Null
                $NSGRuleDestinationPortRange = $Null
                $NSGRuleDestionationAddressPrefix = $Null
                $NSGRuleAccess = $Null
                $NSGRulePriority = $Null
                $NSGRuleDirection = $Null
                $NSGRuleName = $NSGRule.Name
                $NSGRuleProtocol = $NSGRule.Protocol
                $NSGRuleSourcePortRange = $NSGRule.SourcePortRange -join "-"
                $NSGRuleSourceAddressPrefix = $NSGRule.SourceAddressPrefix -join "-"
                $NSGRuleSourceApplicationSecurityGroups = $NSGRule.SourceApplicationSecurityGroups -join "-"
                $NSGRuleDestinationPortRange = $NSGRule.DestinationPortRange -join "-"
                $NSGRuleDestionationAddressPrefix = $NSGRule.DestionationAddressPrefix -join "-"
                $NSGRuleAccess = $NSGRule.Access
                $NSGRulePriority = $NSGRule.Priority
                $NSGRuleDirection = $NSGRule.Direction
                Write-log Warning -message "The script is analyzing $AzSubscriptionRoleAssignementDisplayName ….. --- $iii/$NSGRulesCount"
                
                $Table += New-object PSobject -Property ([Ordered] @{
                        AzSubName                               = $AzSubName;
                        NSGName                                   = $NSGName;
                        NSGResourceGroupName                   = $NSGResourceGroupName;
                        NSGRuleName                               = $NSGRuleName;
                        NSGRuleProtocol                           = $NSGRuleProtocol;
                        NSGRuleAccess                           = $NSGRuleAccess;
                        NSGRulePriority                           = $NSGRulePriority;
                        NSGRuleDirection                       = $NSGRuleDirection;
                        NSGRuleSourcePortRange                   = $NSGRuleSourcePortRange;
                        NSGRuleSourceAddressPrefix               = $NSGRuleSourceAddressPrefix;
                        NSGRuleSourceApplicationSecurityGroups = $NSGRuleSourceApplicationSecurityGroups;
                        NSGRuleDestinationPortRange               = $NSGRuleDestinationPortRange;
                        NSGRuleDestionationAddressPrefix       = $NSGRuleDestionationAddressPrefix;
                        
                    })
                $iii++
            }
            $ii++
        }
        $i++
    }
    
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = ".\Report_All_AzSubscriptions_NSGs_ " + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFilexlsx -TableName "AzSubscriptionsNSGs" -Title "AzSubscriptions NSGs" -TitleBold -WorksheetName "AzSubscriptionsNSGs" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
    
}

#endregion

#region Sentinel
####################################################
############################## Sentinel ################
####################################################
Function Query-MicrosoftSentinel
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$WorkspaceID,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [string]$SubscriptionID,
        [Parameter(Mandatory = $true,
                   Position = 3)]
        [string]$SentinelQuery,
        [Parameter(Mandatory = $true,
                   Position = 4)]
        [int]$Days,
        [Parameter(Mandatory = $true,
                   Position = 5)]
        [pscredential]$Credential
    )
    
    ###### Sentinel Variable
    $SentinelTimeSpan = New-TimeSpan -day $Days
    
    # Establish the connection to Azure (Sentinel)
    Try
    {
        #Write-AzureLog Warning $LogFile "The script will try to connect to Azure (Sentinel)"
        Login-AzAccount -Credential $Credential
        Update-AzConfig -DefaultSubscriptionForLogin $SubscriptionID
        #Write-AzureLog INFO $LogFile "The script successfully connect to Azure (Sentinel)"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-AzureLog Error $LogFile "Failed to connect to Azure (Sentinel)"
        Write-AzureLog Error $LogFile "Failed to run the following CMDLet: $CMDLet"
        Exit
    }
    
    
    # Query Sentinel
    Try
    {
        
        #Write-AzureLog Warning $LogFile "The script will run Sentinel Query : $SentinelQuery within last $Days days"
        $SentinelQueryResults = $Null
        $SentinelQueryResults = Invoke-AzOperationalInsightsQuery -WorkspaceId $WorkspaceID -Query $SentinelQuery -Timespan $SentinelTimeSpan | select Results -ExpandProperty Results
        #Write-AzureLog INFO $LogFile "The script successfully run Sentinel Query within the last $Days days"
        # Generate CSV file:
        $SentinelQueryResultsCount = ($SentinelQueryResults | Measure).count
        #Write-AzureLog Warning $LogFile "$SentinelQueryResultsCount Results from Sentinel Query."
        
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-AzureLog Error $LogFile "Failed to run Sentinel Query within the last $Days days: $ErrorMessage"
        Write-AzureLog Error $LogFile "Failed to run the following CMDLet: $CMDLet"
    }
    $SentinelQueryResults
}

#endregion

#region OpenAI
####################################################
############################## OpenAI ################
####################################################
Function Connect-OpenAI
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$Key
    )
    
    $env:OpenAIKey = $Key
}

Function Ask-ChatGPT
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$Question
    )
    
    Get-GPT3Completion -prompt $Question
}

#endregion