Understanding billing account for Microsoft Customer Agreement (MCA)

Let’s be honest—cloud billing isn’t exactly the most exciting topic. But do you know what’s worse? Opening your Azure bill and feeling like you need a detective’s magnifying glass to figure out what’s going on. 🤯

If you’ve got a Microsoft Customer Agreement (MCA), understanding your billing account is key to keeping your cloud costs in check and avoiding any surprise charges. So, grab a coffee, and let’s break it down in a way that actually makes sense. ☕

What is an MCA Billing Account (And Why Should You Care)?

Think of your MCA billing account as the command center for all your Azure charges. It’s where you manage invoices, payments, and who gets to see (or mess with) your billing details. If Azure billing were a Netflix account, your billing account would be the primary profile—the one that controls everything.

Key Things Your MCA Billing Account Lets You Do:

  • View and manage invoices and payment methods 🧾
  • Set up multiple billing profiles for different teams or departments 🏢
  • Assign roles and permissions (so not everyone can max out the budget!)
  • Track spending across subscriptions 💰

If you’re managing an MCA billing account, congrats! You’ve got the keys to the financial kingdom—use them wisely.

Azure Billing Account: The Big Picture 🎯

Your Azure Billing Account is the home base for all things billing-related in your MCA. It’s where invoices, payments, and spending details live. If you think of Azure like a streaming service, your billing account is your main subscription—everything starts from here.

What You Can Do with an Azure Billing Account:

  • View and manage invoices 🧾
  • Set up and control billing profiles 💳
  • Assign billing roles to different users 👥
  • Track spending across all subscriptions 💰

This is your financial cockpit—control it wisely!

Billing Profiles: Keeping Budgets Organized 🏢

A Billing Profile is like a separate tab on your credit card statement for different teams, projects, or departments. Instead of one giant invoice that makes your head spin, you can split up costs for better organization.

Why Billing Profiles Matter:

  • They generate separate invoices for different teams.
  • You can set up different payment methods for each profile.
  • They help track spending more effectively.

So, if your company has an AI research team and a DevOps team, they can each have their own billing profile—no messy financial mix-ups!

Invoice Sections: Breaking Down Costs Clearly 📄

Under each Billing Profile, you have Invoice Sections. Think of these as subfolders inside your billing profiles—perfect for breaking down costs by project, department, or even specific environments (like Dev vs. Production).

How Invoice Sections Help:

  • You can group charges logically (e.g., marketing vs. engineering).
  • It makes cost tracking super clear.
  • Helps with financial reporting—no more guessing where money went!

If Billing Profiles are the different tabs on your statement, Invoice Sections are like itemized charges—they give you a clearer breakdown.

Subscriptions: Where the Magic Happens

Your Azure Subscriptions are where your actual cloud services live—virtual machines, databases, AI services, you name it. But each subscription needs to be linked to a Billing Profile to be paid for.

Key Things to Know About Subscriptions:

  • They inherit billing settings from their assigned billing profile.
  • You can have multiple subscriptions under one billing account.
  • Each subscription can be assigned to an Invoice Section for better tracking.

Think of it like multiple mobile lines on a family plan. Each line (subscription) has its own usage, but they all roll up into the main bill (billing profile).

Optimizing and Tracking Azure Costs

To effectively manage and optimize your Azure expenditures, consider the following practices:

  • Strategic Structuring: Align your billing profiles and invoice sections with your organization’s hierarchy or project structure. This alignment ensures that invoices reflect your internal financial organization, simplifying reconciliation and reporting.
  • Role-Based Access Control: Assign appropriate roles to team members based on their responsibilities. Azure offers various billing roles, such as Billing Account Owner, Billing Profile Owner, and Invoice Section Owner, each with specific permissions. Implementing role-based access ensures that individuals have the necessary access to perform their tasks without compromising security.
    • Billing Account Owner – The supreme leader of the billing universe. Full access.
    • Billing Profile Owner – Controls billing for one profile (but not the entire account).
    • Billing Profile Contributor – Can manage invoices and payments but not assign roles.
    • Billing Reader – Can see invoices but can’t touch them (great for finance teams!).
  • Regular Monitoring: Utilize Azure’s cost management tools to monitor spending across different billing profiles, invoice sections, and subscriptions. Regular analysis helps in identifying trends, detecting anomalies, and making data-driven decisions to optimize costs.
  • Budgeting and Alerts: Set up budgets and configure alerts for your billing profiles and invoice sections. Proactive notifications enable you to address potential overspending promptly, ensuring adherence to financial plans.

Pro Tips to Avoid Billing Headaches

  1. Assign Roles Wisely – Not everyone needs full access! Keep spending power in the right hands.
  2. Use Billing Profiles for Better Organization – Split billing by department or project to track spending easily.
  3. Enable Cost Management Tools – Azure has built-in cost tracking to help you avoid end-of-month surprises.
  4. Regularly Review Invoices – Set up a habit of checking your invoices to catch any unexpected charges.

Final Thoughts: Take Control of Your Azure Billing 💡

Understanding your MCA Billing Account isn’t just about paying bills—it’s about controlling costs, organizing expenses, and making sure your finance team doesn’t hunt you down. 😅

So next time you log into Azure, don’t panic at your invoice. Instead, think:

  • Is my billing organized?
  • Am I using Billing Profiles and Invoice Sections properly?
  • Do I need to adjust roles to keep spending in check?

Thanks for stopping by. ✌

Guide to Azure Private Endpoint vs Service Endpoint

In the realm of Azure networking, two pivotal features enhance the security and accessibility of your resources: Azure Private Endpoints and Azure Service Endpoints. Understanding their functionalities and differences is crucial for architecting secure and efficient cloud solutions.

Azure Service Endpoints

Azure Service Endpoints extend your virtual network’s identity to Azure services over the Azure backbone network. When a service endpoint is enabled on a subnet, traffic from that subnet to the Azure service remains within Microsoft’s network, reducing exposure to the public internet.

Key Features:

  • Simplified Security: Service endpoints allow you to secure Azure resources to specific virtual networks, enhancing control over which subnets can access particular services.
  • Optimized Routing: Traffic is routed directly through the Azure backbone, potentially reducing latency compared to routes over the public internet.
  • Integration with Network Security Groups (NSGs): You can leverage NSGs to control access, ensuring that only designated subnets or virtual networks can communicate with specific services.

Considerations:

  • Public Endpoint Usage: Despite routing over the Azure backbone, service endpoints connect to the service’s public endpoint, which may not meet stringent security requirements.
  • Azure-Only Access: Service endpoints are designed for traffic originating within Azure. On-premises resources cannot utilize service endpoints and must access services over the public internet.

Azure Private Endpoints

Azure Private Endpoints assign a private IP address from your virtual network to an Azure service, effectively bringing the service into your private address space. This setup ensures that traffic between your virtual network and the service remains entirely within the Azure network, eliminating exposure to the public internet.

Key Features:

  • Private IP Connectivity: Services are accessible via a private IP address within your virtual network, ensuring that all traffic stays within the private network.
  • Enhanced Security: By eliminating public internet exposure, private endpoints are ideal for sensitive data and applications requiring stringent security measures.
  • DNS Integration: Private endpoints require proper DNS configuration to resolve the service’s private IP address. Azure provides automatic DNS resolution, but custom configurations are also supported.

Considerations:

  • Complexity and Cost: Implementing private endpoints can be more complex and may incur additional costs due to the need for DNS configuration and management of private IP addresses.
  • Broader Access: Private endpoints allow access from on-premises networks and other virtual networks, provided they are connected, facilitating hybrid cloud architectures.

Comparison of Azure Service Endpoints and Private Endpoints

FeatureService EndpointsPrivate Endpoints
Connection TypeExtends VNet identity to the service’s public endpoint over Azure backboneAssigns a private IP from your VNet to the service
Security LevelEnhanced security by restricting access to specific VNets; still uses public endpointHighest security with no exposure to public internet
DNS ConfigurationNo changes required; uses public DNSRequires DNS updates to resolve private IPs
Access ScopeOnly from within Azure VNetsAccessible from on-premises and other VNets via private IP
Supported ServicesLimited to specific Azure servicesSupported by a broader range of Azure and third-party services
Use CaseSuitable for scenarios where enhanced security is needed without complex setupIdeal for sensitive data and applications requiring complete isolation

Choosing Between Service Endpoints and Private Endpoints

  • Opt for Service Endpoints if:
    • You need a straightforward way to enhance security for Azure services accessed from within Azure.
    • Your applications do not require complete isolation from the public internet.
    • You prefer minimal configuration without the need for DNS management.
  • Opt for Private Endpoints if:
    • Your applications handle sensitive data necessitating complete isolation from the public internet.
    • You require secure access from on-premises networks or other virtual networks.
    • You are prepared to manage the additional complexity and costs associated with private IP configurations and DNS management.

In summary, both Azure Service Endpoints and Private Endpoints serve to secure access to Azure services, but they cater to different security requirements and use cases. Assess your application’s specific needs to determine the most appropriate solution.

Simplifying Cloud Management with Azure Automation Accounts

Managing cloud resources can feel like juggling too many balls at once—updates, monitoring, compliance, and resource optimization. That’s where Azure Automation Accounts come in—a powerful tool that automates time-consuming and repetitive tasks so IT pros can focus on what truly matters.

In this post, we’ll break down what Azure Automation Accounts are, how they work, their key features, real-world use cases, and how you can get started quickly.

What is an Azure Automation Account?

An Azure Automation Account is a centralized hub in Microsoft Azure where you can manage automation resources. It acts as a container for all the components you need to automate cloud tasks, such as:

  • Runbooks (scripts for tasks)
  • Schedules (timing your scripts)
  • Modules (PowerShell or Python libraries)
  • Hybrid workers (agents that run automation tasks on-prem or in other clouds)

In short, it’s your automation command center.

Key Features

Here are some standout features that make Azure Automation Accounts a must-have:

Runbooks

These are scripts that perform tasks like restarting VMs, rotating keys, or cleaning up unused resources. You can write them in PowerShell, Python, or use the Graphical Runbook Designer for drag-and-drop simplicity.

Scheduling

Automate tasks to run on a set schedule, like checking VM health every morning or scaling services during off-peak hours.

Hybrid Runbook Workers

Need to automate tasks on your on-prem servers? Hybrid Runbook Workers extend your automation capabilities beyond Azure.

Update Management

Keep your Windows and Linux VMs compliant with automated patching and update assessments.

Credential and Certificate Management

Securely store credentials, certificates, and other secrets directly in the automation account, keeping sensitive info safe.

Benefits for IT Professionals

  • Reduce Manual Effort: Save time by automating routine tasks.
  • Improve Consistency: Eliminate human error with repeatable scripts.
  • Boost Efficiency: Focus on strategic projects instead of repetitive admin.
  • Hybrid Flexibility: Automate tasks across on-prem, multi-cloud, and Azure environments.

PowerShell Script to create Azure Automation Account

I put together this PowerShell script to create Azure automation account.

Login to Azure using Connect-AzAccount

This script will,

  • Check and validate the name entered
  • Query Azure to ensure the location value entered is valid
  • Query logged in Azure subscription to validate the resource group name entered
  • Asks for the plan – Basic or Free
  • Asks if you want to generate and assign a new System Identity for this automation account
do {
    $AzAutomationAccountname = Read-Host -Prompt "Enter the name of the Automation Account"
    if ($AzAutomationAccountname -notmatch '^[a-zA-Z][-a-zA-Z0-9]{4,48}[a-zA-Z0-9]$') {
        Write-Host "Invalid name! Please follow these rules:" -ForegroundColor Red
        Write-Host "- Must be 6-50 characters long"
        Write-Host "- Must start with a letter"
        Write-Host "- Must end with a letter or number"
        Write-Host "- Can contain letters, numbers, and hyphens"
        Write-Host "Please try again." -ForegroundColor Yellow
    }
} while ($AzAutomationAccountname -notmatch '^[a-zA-Z][-a-zA-Z0-9]{4,48}[a-zA-Z0-9]$')


do {
    $AzAutomationAccountLocation = Read-Host -Prompt "Enter the location of the Automation Account"
    $validLocations = (Get-AzLocation).Location
    if ($AzAutomationAccountLocation -notin $validLocations) {
        Write-Host "Invalid location! Please enter one of these Azure locations:" -ForegroundColor Red
        $validLocations | Sort-Object | ForEach-Object { Write-Host "- $_" }
        Write-Host "Please try again." -ForegroundColor Yellow
    }
} while ($AzAutomationAccountLocation -notin $validLocations)


do {
    $AzAutomationAccountResourceGroupName = Read-Host -Prompt "Enter the name of the Resource Group for the Automation Account"
    $validResourceGroups = (Get-AzResourceGroup).ResourceGroupName
    if ($AzAutomationAccountResourceGroupName -notin $validResourceGroups) {
        Write-Host "Invalid Resource Group! Please enter one of these existing Resource Groups:" -ForegroundColor Red
        $validResourceGroups | Sort-Object | ForEach-Object { Write-Host "- $_" }
        Write-Host "Please try again." -ForegroundColor Yellow
    }
} while ($AzAutomationAccountResourceGroupName -notin $validResourceGroups)


do {
    Write-Host "Choose the Automation Account plan:"
    Write-Host "1. Basic"
    Write-Host "2. Free"
    $choice = Read-Host -Prompt "Enter your choice (1 or 2)"
    
    switch ($choice) {
        "1" { $AzAutomationAccountplan = "Basic" }
        "2" { $AzAutomationAccountplan = "Free" }
        default {
            Write-Host "Invalid choice! Please enter either 1 or 2" -ForegroundColor Red
            Write-Host "Please try again." -ForegroundColor Yellow
        }
    }
} while ($choice -notin "1","2")


$AzAutomationAccountAssignSystemIdentity = Read-Host -Prompt "Do you want to assign a system identity to the Automation Account? (Y/N)"
if ($AzAutomationAccountAssignSystemIdentity -eq "Y" -or $AzAutomationAccountAssignSystemIdentity -eq "y") {
    $AzAutomationAccountAssignSystemIdentity = $true
} elseif ($AzAutomationAccountAssignSystemIdentity -eq "N" -or $AzAutomationAccountAssignSystemIdentity -eq "n") {
    $AzAutomationAccountAssignSystemIdentity = $false
} else {
    Write-Host "Invalid input! Defaulting to No." -ForegroundColor Red
    $AzAutomationAccountAssignSystemIdentity = $false
}

Write-Host "`nReview your selections:" -ForegroundColor Cyan
Write-Host "Automation Account Name: $AzAutomationAccountname"
Write-Host "Location: $AzAutomationAccountLocation"
Write-Host "Resource Group: $AzAutomationAccountResourceGroupName"
Write-Host "Plan: $AzAutomationAccountplan"
Write-Host "System Identity: $(if ($AzAutomationAccountAssignSystemIdentity) { 'Yes' } else { 'No' })"

$confirm = Read-Host -Prompt "`nDo you want to proceed with these settings? (Y/N)"
if ($confirm -ne 'Y' -and $confirm -ne 'y') {
    Write-Host "Operation cancelled by user." -ForegroundColor Yellow
    exit
}


if ($AzAutomationAccountAssignSystemIdentity) {
    New-AzAutomationAccount -Name $AzAutomationAccountname -Location $AzAutomationAccountLocation -ResourceGroupName $AzAutomationAccountResourceGroupName -Plan $AzAutomationAccountplan -AssignSystemIdentity
} else {
    New-AzAutomationAccount -Name $AzAutomationAccountname -Location $AzAutomationAccountLocation -ResourceGroupName $AzAutomationAccountResourceGroupName -Plan $AzAutomationAccountplan
}

Azure Automation Accounts are an essential part of a smart cloud strategy. By leveraging them, IT professionals can reduce overhead, improve reliability, and maintain control over sprawling environments.

Whether you’re managing a handful of VMs or an enterprise-grade hybrid infrastructure, automation is your silent workhorse—and Azure makes it incredibly approachable.

Thank you for stopping by. ✌️

Azure Role-Based Access: Who’s Got the Keys to the Cloud Castle?

Alright, let’s talk about Azure Role-Based Access Control (RBAC)—the bouncer at the club, the gatekeeper of your cloud kingdom, the difference between “Oops, I deleted the production database” and “Phew, good thing I didn’t have permission for that.”

If you’re working with Microsoft Azure, RBAC is a must-know. It’s how you control who can do what in your cloud environment. Let’s break it down in a fun, easy-to-digest way.


What is Azure RBAC, and Why Should You Care?

Think of Azure RBAC like a high-tech office building with keycards. Not everyone should have access to every room, right? Your interns shouldn’t be able to access the CEO’s private office, and the janitor doesn’t need the nuclear launch codes.

RBAC works the same way in Azure:

  • You assign roles to users, groups, or applications instead of just giving them full access.
  • It’s based on the principle of least privilege, meaning people only get access to what they need—nothing more, nothing less.
  • It prevents chaos. Because let’s be real, one accidental click from an over-permissioned user can lead to disaster.

The Three Key Pieces of RBAC

Azure RBAC is built on three main pieces:

  1. Roles: These define what someone can do. Examples:
    • Owner – The boss. Can do anything and everything.
    • Contributor – Can create and manage resources but can’t assign roles.
    • Reader – Can look, but not touch.
    • Custom Roles – If the built-in roles aren’t enough, you can create your own.
  2. Scope: This defines where the role applies. It can be at:
    • Subscription level (the whole kingdom)
    • Resource group level (a city inside the kingdom)
    • Specific resources (a single castle or shop)
  3. Assignments: This is the who gets what role part. Assign a user, group, or service principal to a role at a given scope, and boom—permissions granted.

Real-World Example: The Coffee Shop Analogy ☕

Imagine you’re running a coffee shop:

  • The Owner (you) can do everything—order supplies, hire staff, make coffee, or even shut down the store.
  • The Baristas (contributors) can make coffee and manage the store but can’t hire or fire anyone.
  • The Customers (readers) can look at the menu, enjoy their coffee, but they’re not allowed behind the counter.

That’s Azure RBAC in action. Everyone gets access to what they need, but no one is accidentally pressing the “shutdown entire store” button.


Common RBAC Mistakes (And How to Avoid Them)

  1. Giving Everyone Owner or Contributor Roles – That’s like handing out master keys to your entire office. Keep permissions minimal!
  2. Not Using Groups – Assigning roles individually? Big mistake. Use Azure AD groups to manage permissions efficiently.
  3. Ignoring Scope – Always assign roles at the lowest necessary level to avoid over-permissioning.
  4. Forgetting to Review Roles Regularly – People leave jobs, projects change, and roles should be updated accordingly.

Final Thoughts: Lock It Down, But Keep It Practical

Azure RBAC is all about control, security, and making sure the right people have the right access. It’s not just an IT thing—it’s about keeping your cloud environment safe and sane.

So next time you’re setting up roles in Azure, ask yourself:

  • Does this person really need this level of access?
  • Could I use a lower scope?
  • Am I following best practices?

Get it right, and your cloud stays secure. Get it wrong, and… well, let’s just say you don’t want to be the person who accidentally gives the intern the power to delete the company’s entire infrastructure.

Thank you for stopping by.✌

How to Automatically Download and Use Azure Public IP Ranges with PowerShell

If you work with firewalls, proxies, or any system that restricts traffic based on IP addresses, you’re likely familiar with the challenges of maintaining access to dynamic cloud infrastructure. Microsoft understands this, which is why they publish the Azure IP Ranges and Service Tags – Public Cloud dataset — a JSON file containing up-to-date IP address ranges used by Azure services.

Why Microsoft Publishes Azure IP Ranges

Microsoft Azure’s cloud infrastructure spans global data centers, with thousands of services running behind constantly shifting sets of IP addresses. To help organizations:

  • Configure firewalls and security appliances
  • Whitelist Azure service IPs
  • Meet compliance or policy needs
  • Route traffic appropriately

…Microsoft provides this public JSON file that includes IP ranges tied to Service Tags like Storage, Sql, AppService, and many others, broken down by region.

If you are using Azure Firewall, then you can use these service tags directly in your firewall rules. More information can be found here. If you are using some other firewall, then you need to check if they support service tags directly e.g., Palo Alto Networks & External Dynamic Lists (EDL).

If you don’t have support for service tags in your firewall, then you need to use IP address prefixes directly. This is not ideal, since you need to update your firewall rules every time when new IP address prefixes are added or removed. This is why automating this process is important.


How Often Is the Data Updated?

Microsoft typically updates the Azure IP Ranges and Service Tags – Public Cloud file weekly, usually every Monday. Updates can reflect:

  • New IPs added for expanding infrastructure
  • Old ranges removed or reallocated
  • Changes to service or region mappings

Each release includes a "changeNumber" field and a "version" field to help you detect updates. Automation is key here — hence the script!


Changes, Changes…

Azure public IP addresses can change weekly! What does that mean for us?

Every week, there may be new IP addresses added to the list. Others may be removed if they’re no longer in use by Azure.

Why does that matter?

Let’s say an on-prem application needs access to an AzureSQL database, you previously added its IPs to your firewall allow-list. Then Azure updates its IP ranges, and the on-prem application keeps using the same IP or IP ranges that’s not in your allow-list. Boom — access denied. Not because you intended to block it, but because you didn’t know about the change.

It’s not just about adding the new IPs. You also need to handle removals to prevent your allow-lists from becoming bloated and insecure.

This isn’t a new problem in networking. But in Azure, the pace of change is faster — often weekly — and automation becomes essential.


How Is the JSON File Structured?

The JSON file is well-organized and structured to support automation. Here’s what it generally looks like:

jsonCopyEdit{
  "changeNumber": 20250401,
  "cloud": "Public",
  "values": [
    {
      "name": "AppService.WestUS",
      "id": "AppService.WestUS",
      "properties": {
        "region": "westus",
        "platform": "Azure",
        "systemService": "AppService",
        "addressPrefixes": [
          "13.64.0.0/18",
          "40.112.0.0/16"
        ]
      }
    },
    ...
  ]
}

Key fields:

  • values: Array of service tag entries
  • name / id: Service and region
  • properties.addressPrefixes: List of IP ranges (in CIDR format)

You can easily filter entries by region, service tag, or even specific prefixes depending on your needs.


Common Use Cases for Downloading Azure IPs

There are many real-world situations where access to this list is helpful:

  • Firewall Whitelisting: Allow only Azure Storage or Sql service traffic from a specific region.
  • Cloud Egress Policies: Identify what your workloads are connecting to by cross-referencing logs with Azure-owned IPs.
  • Network Audits & Compliance: Ensure your infrastructure is only communicating with approved external services.
  • CDN or WAF Configurations: Enable access to Azure Front Door, App Service, or other endpoints behind the scenes.
  • Automation Pipelines: Pull the list programmatically during CI/CD to dynamically configure network security settings.

PowerShell Script to Download the File

To help automate this process, I wrote a PowerShell script that downloads the latest Azure IP Ranges JSON file:

What this script does,

  • Fetches the HTML content of the page https://www.microsoft.com/en-us/download/details.aspx?id=56519 using Invoke-WebRequest.
  • Extracts the JSON file URL from the page content using a regex match.
  • Creates a folder named json_files if it does not already exist.
  • Extracts the JSON file name from the URL and constructs the file path within the json_files folder.
  • Checks if the JSON file already exists:
    • If it exists, skips the download.
    • If it does not exist, downloads the JSON file to the json_files folder.
  • Parses the downloaded JSON file into a PowerShell object using ConvertFrom-Json.
  • Creates a timestamped folder named AzureServicetags_<timestamp> in the directory called ‘AzureServicetags’ in the current directory.
  • Creates three subfolders within the timestamped folder:
    • All_IPs for all IP addresses.
    • IPv4_IPs for IPv4 addresses.
    • IPv6_IPs for IPv6 addresses.
  • Iterates through each service tag in the JSON content:
    • Extracts the service name and its associated IP address prefixes.
    • Separates the IP addresses into IPv4 and IPv6 categories using regex matching.
    • Creates text files for:
      • All IP addresses.
      • IPv4 addresses.
      • IPv6 addresses.
    • Writes the respective IP addresses into the corresponding text files.
    • Outputs a message indicating the creation of files for each service.
  • Skips services that do not have valid address prefixes and outputs a warning message.
  • Outputs a message if the JSON URL is not found.
# Define the URL of the download page
$pageUrl = "https://www.microsoft.com/en-us/download/details.aspx?id=56519"

# Fetch the page source
$response = Invoke-WebRequest -Uri $pageUrl -UseBasicParsing

# Extract the JSON URL for 'url'
$jsonUrl = ($response.Content -match '"url":"(https://download\.microsoft\.com/download/[^"]+)"') | Out-Null
$jsonUrl = $matches[1]

# Output the JSON URL
if ($jsonUrl) {
    Write-Output "JSON URL: $jsonUrl"

    # Create the folder 'json_files' if it doesn't exist
    $jsonFolder = "json_files"
    if (-not (Test-Path -Path $jsonFolder)) {
        New-Item -ItemType Directory -Path $jsonFolder | Out-Null
    }

    # Extract the file name from the JSON URL
    $jsonFileName = $jsonUrl.Split("/")[-1]
    $jsonFilePath = Join-Path -Path $jsonFolder -ChildPath $jsonFileName

    # Check if the JSON file already exists
    if (Test-Path -Path $jsonFilePath) {
        Write-Output "File '$jsonFileName' already exists. Skipping download."
    }
    else {
        # Download the JSON file into the 'json_files' folder
        Invoke-WebRequest -Uri $jsonUrl -OutFile $jsonFilePath
        Write-Output "Downloaded JSON file: $jsonFileName"
    }

    # Parse the JSON file
    $jsonContent = Get-Content -Path $jsonFilePath -Raw | ConvertFrom-Json

    # Create a folder with the current date and time stamp
    $timestamp = Get-Date -Format "yyyy-MM-dd_HH-mm"
    $folderName = ".\AzureServicetags\AzureServicetags_$timestamp"
    New-Item -ItemType Directory -Path $folderName | Out-Null

    # Create subfolders for All_IPs, IPv4_IPs, and IPv6_IPs
    $allIPsFolder = Join-Path -Path $folderName -ChildPath "All_IPs"
    $ipv4Folder = Join-Path -Path $folderName -ChildPath "IPv4_IPs"
    $ipv6Folder = Join-Path -Path $folderName -ChildPath "IPv6_IPs"

    foreach ($subFolder in @($allIPsFolder, $ipv4Folder, $ipv6Folder)) {
        if (-not (Test-Path -Path $subFolder)) {
            New-Item -ItemType Directory -Path $subFolder | Out-Null
        }
    }

    # Iterate through each service tag and create text files
    foreach ($service in $jsonContent.values) {
        $serviceName = $service.name

        if ($service -and $service.properties -and $service.properties.addressPrefixes) {
            $ipAddresses = $service.properties.addressPrefixes
            $ipv4Addresses = $ipAddresses | Where-Object { $_ -match '\.' -and $_ -notmatch '\:' }
            $ipv6Addresses = $ipAddresses | Where-Object { $_ -match '\:' }

            # Create files for all IPs, IPv4 IPs, and IPv6 IPs
            $allIPsFilePath = Join-Path -Path $allIPsFolder -ChildPath "$serviceName`_all_IPs.txt"
            $ipv4FilePath = Join-Path -Path $ipv4Folder -ChildPath "$serviceName`_v4_IPs.txt"
            $ipv6FilePath = Join-Path -Path $ipv6Folder -ChildPath "$serviceName`_v6_IPs.txt"

            $ipAddresses | Out-File -FilePath $allIPsFilePath -Encoding UTF8
            $ipv4Addresses | Out-File -FilePath $ipv4FilePath -Encoding UTF8
            $ipv6Addresses | Out-File -FilePath $ipv6FilePath -Encoding UTF8

            Write-Output "Created files for service: $serviceName"
        }
        else {
            Write-Warning "Service '$serviceName' does not have valid address prefixes. Skipping."
        }
    }
}
else {
    Write-Output "JSON URL not found."
}

Thanks for stopping by. ✌