Search code examples
azurepowershellazure-functionsazure-storageazure-cli

Az Powershell Module - says "Cannot find storage account with name xxx" but it exists


I've run into a snag with my powershell script that builds an azure function & all its dependencies.

This is what's happening: (i'm doing it manually here to demo...)

I request the storage account information like this:

 PS C:\Users\me\>  Get-AzStorageAccount -ResourceGroupName widget-resource-group                


StorageAccountName     ResourceGroupName PrimaryLocation SkuName      Kind      AccessTier CreationTime          ProvisioningState EnableHttpsTrafficOnly LargeFileShares
------------------     ----------------- --------------- -------      ----      ---------- ------------          ----------------- ---------------------- ---------------
widgetx4ge6v27rlgdk widget-resource-group eastus          Standard_LRS StorageV2 Hot        2022-03-10 2:00:26 PM Succeeded         True

It comes back with the correct information. So then I try to get the connection string like this:

PS C:\Users\me> func azure storage fetch-connection-string widgetx4ge6v27rlgdk                 

Cannot find storage account with name widgetx4ge6v27rlgdk 

But it says it can't find the storage account. The actual code looks like this:

# Look up function app name that was dynamically created by ARM template:
$AZ_FUNCTION_APP = Get-AzFunctionApp -ResourceGroupName $currentEnv.AZ_RESOURCE_GROUP_NAME

#look up the storage account name for this resource group. 
$AZ_STORAGE_ACCOUNT = Get-AzStorageAccount -ResourceGroupName $currentEnv.AZ_RESOURCE_GROUP_NAME
Write-Output $AZ_STORAGE_ACCOUNT.StorageAccountName

# Get new connection string for the storage account.
func azure storage fetch-connection-string $AZ_STORAGE_ACCOUNT.StorageAccountName

When the code runs, everything works until the call to "func azure storage fetch-connection-string".

Any tips on what I'm missing?

Edit 1

In case it helps, this logic works just fine when I run it against Tenant 1, Subscription A. But for Tenant 1, Subscription B it bombs. I've made sure the service account principle it runs under is contributor on both subscriptions. And for what it's worth, the script is able to create the resource group and many of the resources inside. It's just hat when I try to get the connection string, it bombs. It also bombs further down in the script when it tries to deploy the functions in my function app. The error message though is similar - it complains that it can't find the function app that I just finished creating.

Edit 2

So I figured out the problm but not sure how to fix it in a nice / simple way. For 90% of the script, including login, i'm using the new Az Powershell modules. However, the "func azure" tool relies on login information provided by the az cli. (that seems to be cached??)

To get you on the same page, here's the relevant part of the code in the script:

$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $AZ_DEPLOYMENT_CLIENT_ID, $Secure2

#Connect
Connect-AzAccount -ServicePrincipal -TenantId $AZ_TENANT_ID -Credential $Credential

#OPTIONAL - List the subscriptions available to the current User
Get-Azcontext -ListAvailable

#Set the subscription context to subscription 2
Set-Azcontext -Subscription $AZ_SUBSCRIPTION_ID -Tenant $AZ_TENANT_ID

#Create a new resource group
New-AzResourceGroup -Name $AZ_RESOURCE_GROUP_NAME -Location $AZ_RESOURCE_LOCATION -Force

New-AzResourceGroupDeployment -ResourceGroupName $AZ_RESOURCE_GROUP_NAME -TemplateFile (Join-Path $PSScriptRoot "./artifacts/widget-resources.json")

# Look up function app name that was dynamically created by ARM template:
$AZ_FUNCTION_APP = Get-AzFunctionApp -ResourceGroupName $AZ_RESOURCE_GROUP_NAME

#look up the storage account name for this resource group. 
$AZ_STORAGE_ACCOUNT = Get-AzStorageAccount -ResourceGroupName $AZ_RESOURCE_GROUP_NAME
Write-Output $AZ_STORAGE_ACCOUNT.StorageAccountName

# this is where it is failing because it is using a subscription that is visible to az cli.
func azure storage fetch-connection-string $AZ_STORAGE_ACCOUNT.StorageAccountName

Here's what I did to troubleshoot from a powershell cli:

 az account list

That returns this:

  {
    "cloudName": "AzureCloud",
    "homeTenantId": "asdf-asdf-asdf-asdf-12312312313",
    "id": "[guid]",
    "isDefault": false,
    "managedByTenants": [],
    "name": "subscription-1",
    "state": "Enabled",
    "tenantId": "[our-tenant-id]",
    "user": {
      "name": "[another-guid]",
      "type": "servicePrincipal"
    }
  }

When I ran the above command, it only returned one subscription called "subscription-1" for discussion purposes. It isn't/wasn't the one that the rest of the script was working with. The rest of script was dealing with subscription 2 As I test, I added the following lines of code just before call func azure storage:

az login --service-principal --username $AZ_APPLICATION_CLIENT_ID --password $AZ_SECRET --tenant $AZ_TENANT --allow-no-subscriptions

#set the subscription we want to use
az account set --subscription $subscription2

func azure storage fetch-connection-string $AZ_STORAGE_ACCOUNT.StorageAccountName

And now it finds the correct subscription and resource group / storage account. And now when I run az account list again, it shows me both subscriptions.

One addition comment / observation. Once the az login / az account set has been run with the desired subscription id, i've noticed that I can remove the az login and account set logic from the script and it just uses the cached values. I'm not saying this is what I want to do ... cuz I think it' best to be explicit. But just an observation which explains what bit me in the first place.

So my question is... is there anyway to avoid having to log in twice - once with az cli and another time with the Az Powerhsell modules? I'm thinking of just abandoning the Az Powershell module and just rewriting everything in just az cli.

But asking the community to see if there's a better way to do this.

EDIT 3

Based on the docs for the azure core functions tools, technically I should be able to use the powershell modules or the cli:

https://learn.microsoft.com/en-us/azure/azure-functions/functions-run-local?tabs=v4%2Cwindows%2Ccsharp%2Cportal%2Cbash#publish

"You must have the Azure CLI or Azure PowerShell installed locally to be able to publish to Azure from Core Tools."


Solution

  • The issue was that the azure core functions tool is using the cached az account list to find my resources. So in other words, unbeknownst to me, the func method was using az cli, whereas the rest of the script is using the new Az Powershell modules.

    For now, I've just rewritten everything in az cli syntax, and am happy with that. But per the docs it seems that the azure core functions tools should be able to work with either az cli or az powershell. Will open a separate question that addresses that point. For now, my script is working again.