How-to-control-invoice-number-on-Azure


Had some fun the last day before Easter vacation. Created a script that downloads all invoices for each subscription in an Azure tenant.

We have found it cumbersome to control the Azure invoice number on the master card invoices sent from the economics department. The invoice number looks something like this “E0000XXXXX” and connecting this to a subscription is hard.

Our solution to the problem was a script downloading the invoices with a script, and using Adobe Acrobat Reader to find the invoice number with advanced search. In this post I go through the script and how you can use Adobe Acrobat to find the invoice number related to the correct subscription.

First I did was creating an advanced PowerShell function, this is specified by using the CmdletBinding attribute under the function name. The script takes two default parameters. The first one is $FolderPath, this is the path where all the invoices gets downloaded to.

Note: In the script I have not added checks to see if the path exists or creates the path if it doesn’t exist. To avoid error, make sure to use a path that exists or just use the default path.

The second parameter is $MaxCount, this specifies the count of most recent invoices to download. If you want to download the 10 latest invoices as an example, you set the $MaxCount to 10.

# Starting with creating an advanced function and the parameters
function Get-AzureBillingInformation {
    [CmdletBinding()]
    param (
        # Folder Path for storing invoices
        [Parameter(Mandatory = $false)]
        [String]
        $FolderPath = "C:\Temp\AzureInvoice",
        # Limit of invoices to download
        [Parameter(Mandatory = $false)]
        [int]
        $MaxCount = 1
    )
}

Next step in the script is the begin block. The begin block is used for one time pre-processing, and here I’m using it to get the timestamp from when the script was initiated. The $StartTime variable is used later to calculate how long it took to download all the invoices from the subscriptions.

# The begin block
begin {
        $StartTime = Get-Date
    }

Next, is the process block. This is used to for multiple record processing and is the main part of the script. This is where the action happens.

First I created three variables; the $Subscriptions variable is used to store all subscriptions i gets from the Get-AzSubscription cmdlet, $InvoiceArray is used to store the invoices per subscriptions, and the $TotalSubscriptions counts the total number of subscriptions in the Azure tenant.

Then I’m looping through all the subscriptions stored in the $Subscription variable. Then using the Set-AzContext cmdlet to set the context to the subscriptions specified in the variable. This is for getting the invoice(s) connected to each subscription, this is stored in the $InvoiceArray.

Then I’m looping through the $InvoiceArray to download the invoice(s) for each subscription. Here I added a simple check to see if a file with the invoice name exists in the specified folder, if it does the loop breaks. If not, the script continue and creates a file with the invoice name, this only creates empty files to avoid getting an error message from the Invoke-WebRequest cmdlet, that says something like “Path not found” when asking it to output the file to a path that does not exists.

When the files are created, the Invoke-WebRequest cmdlet downloads the file from the Azure Portal and stores it in the specified path. Each file created in previous step will now be an subscription invoice.

# The process block
process {
        $Subscriptions = Get-AzSubscription
        $InvoiceArray = @()
        $TotalSubscriptions = 0

        foreach ($Subscription in $Subscriptions) {
            $TotalSubscriptions++
            $SubscriptionName = $Subscription.Name
            Write-Verbose "Setting Subscription Context to: $SubscriptionName.."
            Set-AzContext -Subscription "$SubscriptionName"
            Write-Verbose "Getting invoice information for: $SubscriptionName.."
            $InvoiceArray += (Get-AzBillingInvoice -MaxCount $MaxCount -GenerateDownloadUrl | Select-Object Name, DownloadUrl)
            Write-Output ""
        }
        foreach ($Invoice in $InvoiceArray) {
            $Name = $Invoice.Name
            $Url = $Invoice.DownloadUrl
            if (Test-Path "$FolderPath\$Name.pdf") {
                Write-Host -ForegroundColor Red "File $Name.pdf already exists.."
                exit
            }
            else {
                Write-Host -ForegroundColor Green "`nCreating invoice file: $Name.pdf.."
                New-Item -Path "C:\temp\AzureInvoice\" -Name "$Name.pdf" -ItemType File
                Write-Verbose "Downloading invoice: $Name.pdf.."
                Invoke-WebRequest -Uri $Url -Outfile "$FolderPath\$Name.pdf"
            }
        }
    }

At last we have the end block, this is used for one time post-processing. In this case, to output the time it took downloading the specified amount of invoices per subscription and the total count of subscriptions. Using the $StartTime variable from the begin block divided by the time the script finished, and the $TotalSubscriptions from the start of the process block.

# The end block
end {
    Write-Output ""
    Write-Verbose "Outputting time taken to download all the invoices.."
    Write-Host -ForegroundColor Green "Time taken to download $MaxCount invoice(s) per subscription, from a total of $TotalSubscriptions subscriptions: $((Get-Date).Subtract($StartTime).Seconds) second(s)"
}

Also I added a help comment for what the script does and how to use it.

# The powershell help manual for the command
<#
.SYNOPSIS
    Downloads subscriptions invoices from the Azure Portal.
.EXAMPLE
    PS C:\> Get-AzureBillingInformation
    Uses default values and saves the three latest subscription invoices to C:\temp\AzureInvoice
.EXAMPLE
    PS C:\> Get-AzureBillingInformation -MaxCount 1
    Saves the latest subscription invoices to C:\temp\AzureInvoice
.PARAMETER FolderPath
    Defines where to store the downloaded invoices.
.PARAMETER MaxCount
    Specifies how many invoices to download back in time.
.NOTES
    Use Connect-AzAccount to logon the portal. Also you need permission to Billing information.
    Use . .\Get-AzureBillingInformation.ps1 to load script into memory
    To find out which connect the encrypted invoice number on the credit card invoice to a Azure
    Subscription, use Adobe Acrobat > Edit > Advanced Search > Specify All PDF in selected folder > Enter invoice number > Then you should you find the correct invoice
#>

Here is the complete script.

<#
.SYNOPSIS
    Downloads subscriptions invoices from the Azure Portal.
.EXAMPLE
    PS C:\> Get-AzureBillingInformation
    Uses default values and saves the three latest subscription invoices to C:\temp\AzureInvoice
.EXAMPLE
    PS C:\> Get-AzureBillingInformation -MaxCount 1
    Saves the latest subscription invoices to C:\temp\AzureInvoice
.PARAMETER FolderPath
    Defines where to store the downloaded invoices.
.PARAMETER MaxCount
    Specifies how many invoices to download back in time.
.NOTES
    Use Connect-AzAccount to logon the portal. Also you need permission to Billing information.
    Use . .\Get-AzureBillingInformation.ps1 to load script into memory
    To find out which connect the encrypted invoice number on the credit card invoice to a Azure
    Subscription, use Adobe Acrobat > Edit > Advanced Search > Specify All PDF in selected folder > Enter invoice number > Then you should you find the correct invoice
#>
function Get-AzureBillingInformation {
    [CmdletBinding()]
    param (
        # Folder Path for storing invoices
        [Parameter(Mandatory = $false)]
        [String]
        $FolderPath = "C:\Temp\AzureInvoice",
        # Limit of invoices to download
        [Parameter(Mandatory = $false)]
        [int]
        $MaxCount = 1
    )
    begin {
        $StartTime = Get-Date
    }
    process {
        $Subscriptions = Get-AzSubscription
        $InvoiceArray = @()
        $TotalSubscriptions = 0

        foreach ($Subscription in $Subscriptions) {
            $TotalSubscriptions++
            $SubscriptionName = $Subscription.Name
            Write-Verbose "Setting Subscription Context to: $SubscriptionName.."
            Set-AzContext -Subscription "$SubscriptionName"
            Write-Verbose "Getting invoice information for: $SubscriptionName.."
            $InvoiceArray += (Get-AzBillingInvoice -MaxCount $MaxCount -GenerateDownloadUrl | Select-Object Name, DownloadUrl)
            Write-Output ""
        }
        foreach ($Invoice in $InvoiceArray) {
            $Name = $Invoice.Name
            $Url = $Invoice.DownloadUrl
            if (Test-Path "$FolderPath\$Name.pdf") {
                Write-Host -ForegroundColor Red "File $Name.pdf already exists.."
                exit
            }
            else {
                Write-Host -ForegroundColor Green "`nCreating invoice file: $Name.pdf.."
                New-Item -Path "C:\temp\AzureInvoice\" -Name "$Name.pdf" -ItemType File

                Write-Verbose "Downloading invoice: $Name.pdf.."
                Invoke-WebRequest -Uri $Url -Outfile "$FolderPath\$Name.pdf"
            }
        }
    }
    end {
        Write-Output ""
        Write-Verbose "Outputting time taken to download all the invoices.."
        Write-Host -ForegroundColor Green "Time taken to download $MaxCount invoice(s) per subscription, from a total of $TotalSubscriptions subscriptions: $((Get-Date).Subtract($StartTime).Seconds) second(s)"
    }
}

That was the script for downloading invoices from Azure. Now, over to how we find the subscription connected to the invoice number.

How to use Adobe Acrobat to find correct invoice number

To find the correct invoice number using Adobe Acrobat you can follow the steps below:

If you don’t have it installed you can get it from https://get.adobe.com/no/reader/, the free version works just fine.

First, open Adobe Acrobat Reader DC.

Then go to Edit > Advanced Search

Acrobat opening Advanced Search window

Open the Dropdown list and select Browse for Location and select C:\temp\AzureInvoice

Acrobat search window

Then enter the Invoice number you want to find, can look something like E0000XXXXX.

Then hit the search button.

Acrobat search phrase

This should list out something like below. When opening the pdf in the search result, you should see the subscription correlated to the invoice number. In this case I won’t show the actual invoice. So the steps ends here.

Acrobat search result

This was a fun little project on a Friday afternoon. Hopefully will this save a lot of time, instead of searching through one by one invoice in the Azure Portal. Hope you enjoyed it and can find it useful.