Get Azure Storage Account Key inside Powershell Function App - azure

I am trying to get the Key of a Storage Account from inside a Powershell Function App under the same Resource Group "rg-mobileplans".
I am certain I have the correct Azure Context and when listing all the Storage Accounts I see the one I am trying to retrieve the key from - "stmobileplansstaging".
Write-Host ((Get-AzContext).Subscription)
Write-Host (Get-AzStorageAccount -ResourceGroupName rg-mobileplans).StorageAccountName
Output:
<Subscription ID Hidden for Privacy>
stmobileplansstaging storageaccountrgmob83d8
But when I try to get the key itself I get an error message that the Storage Account Could not be found.
Get-AzStorageAccountKey -ResourceGroupName rg-mobileplans -AccountName stmobileplansstaging
Output:
ERROR: Get-AzStorageAccountKey : The Resource 'Microsoft.Storage/storageAccounts/stmobileplansstaging ' under resource group 'rg-mobileplans' was not found. For more details please go to https://aka.ms/ARMResourceNotFoundFix
Keep in mind that I am running these commands from a Function App. Running them from Powershell works.
I have created a System Managed Identity for the Function App and gave it "Owner" access to the entire "rg-mobileplans" Resource Group and the "stmobileplansstaging" Storage Account.
What am I missing?

I just realized what the problem is. In the script the storage account name is given through a tag. The name had a space at the end. When running the get / list storage account commands it's OK and the commands succeed because the name of the account is probably at the end, but for getting the key, underneath a POST call is being made and the URL looked something like "http://.../storage/stmobileplansstaging /rest-of-the-uri". Notice the space in the middle of the URI which broke everything.

Related

Error result using New-AzApplicationInsightsContinuousExport - Can not perform requested operation on nested resource. Parent resource

I am trying to use the New-AzApplicationInsightsContinuousExport in the powershell since the Continuous Export feature is currently not available unless we migrate the current resource for application insight in workspace-based application resource. Unfortunately we do not have the authority to do it for now so thats why we are using the alternative method through powershell. I followed the instructions and created the sample storage creation found in the document of microsoft. Then after that used the sample command "New-AzApplicationInsightsContinuousExport". Did change the value based on the settings we have and execute it. But I encountered an error which is "Can not perform requested operation on nested resource. Parent resource". Been trying to find how to solve but unfortunately, I am stuck. Would someone help or direct me what should I do on this? Thanks! I posted the image of the command i executed.
enter image description here
enter image description here
I tried different approach of values that on the parameters that I think might work but its not working also. I also checked the "appinsighttest1" storage account configuration that was created by checking the settings, network, keys and other that might enable/visible for the command to work. My idea is the reason that it is not found maybe i have to enable something the storage account configuration. But right now i cant get it to work.
Error result using New-AzApplicationInsightsContinuousExport - Can not perform requested operation on nested resource. Parent resource:
"Parent resource 'test' not found: It means that no application insight resource with the name "test" has been created in Azure. You must first create an application insight in Azure Portal before using New-AzApplicationInsightContinuousexport.
I created in my environment as shown:
Using MSDoc as a reference, I tried in my environment with few modifications and successfully enabled continuous export with the respective command.
Script to run:
$context = $context = New-AzStorageContext -StorageAccountName "xxxstorageaccountname" -StorageAccountKey "xxxStorageaccountkey=="
$sastn = New-AzStorageContainerSASToken -Name <container> -Context $context -ExpiryTime (Get-Date).AddYears(50) -Permission w
$SASuri = "https://<storageaccount>.blob.core.windows.net/<containername>" + $sastn
New-AzApplicationInsightsContinuousExport -ResourceGroupName "<ResourceGroupName>" -Name "<applicationinsightname>" -DocumentType "Request","Trace", "Custom Event" -StorageAccountId "/subscriptions/<subscriptionID>/resourcegroups/<ResourceGroupName>/providers/Microsoft.Storage/storageAccounts/<storageaccount>" -StorageLocation EastUS -StorageSASUri $SASuri -DestinationType Blob
Output:
Note: This error might occur when you do not have enough right (access) to give/modify the permissions or roles. Assign "Storage Blob Data Owner" role for the storage account.

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."
Yes, using a mix of azcli and azure powershell, as they are their seperate entities in their own right, you would need to login to each of them individually.
And yes, you are right its better to ditch of them and choose one or the other ! Just much cleaner that way
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.

Creating Azure API Management using deleted name results in name "already in use" error

I previously created and subsequently deleted an Azure API Management service using Terraform. It disappeared in Azure Portal. A few hours after that, when I tried to recreate API Management with the same name, I got this error in the Azure Portal :
"name already in use. Please select a different name."
Also got similar error in Terraform as well.
Anyone knows why the name cannot be reused even though I am no longer seeing that name in my resource group?
Check if your APIM service have been soft deleted or not. If the resource has been soft-deleted, and you want to create a new one with the same name,what you need to do is purge the resource and then recreate.
Get a soft-deleted instance by name:
GET https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.ApiManagement/locations/{location}/deletedservices/{serviceName}?api-version=2020-06-01-preview
List all soft-deleted instances for a given subscription:
GET https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.ApiManagement/deletedservices?api-version=2020-06-01-preview
Recover a deleted APIM instance:
PUT https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroup}/providers/Microsoft.ApiManagement/service/{apimServiceName}?api-version=2020-06-01-preview
Purge a soft-deleted APIM instance:
DELETE https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.ApiManagement/locations/{location}/deletedservices/{serviceName}?api-version=2020-06-01-preview
I wrote an article with some PowerShell code (function) that wraps the REST calls, so you can just call the function with a few parameters like below.
Purge-ApiManagementInstance -SubscriptionId $subId -Location $location -Name $apimInstanceName
https://www.linkedin.com/pulse/purging-azure-api-management-instance-james-hughes/
As others already mentioned, your instance has been soft deleted.
You need terraform to purge the instance on destroy, this is done by adding some config options on provider section
https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/guides/features-block#api_management
provider "azurerm" {
api_management {
# does not seem to work, insufficient rights?
purge_soft_delete_on_destroy = true
# as of now next attribute exists only on docs, never worked for me
# https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/guides/features-block#api_management
#recover_soft_deleted_api_management = false
}
----
}
According to terraform docs your SP also needs to have recover permission.
You can also use az rest to delete it
az rest --method delete --header "Accept=application/json" -u 'https://management.azure.com/subscriptions/123-123-123/providers/Microsoft.ApiManagement/locations/[eastus]/deletedservices/cloud-devops-test?api-version=2020-06-01-preview'
Also, you can use AZ CLI for that now:
az apim deletedservice purge --help
example:
az apim deletedservice purge -l APIM_LOCALTION -n APIM_NAME

Remove Azure Storage Account Key

I need to remove any Authentication Key that the Storage Accounts of my subscriptions. Do you know if there is any way to remove it? I was looking for a cmdlet in powershell to do it but was unable to find it.
I was able to retrieve the list of Storage Accounts and check if there is an authentication key set, however I was unable to remove them. I tried to set them as null, but it didn't work
$colStorageAccounts = Get-AzureRMStorageAccount
for ($objStorageAccount in $colStorageAccounts)
{
$objAccountKey = Get-AzureRMStorageAccountKey -ResourceGroupName $objStorageAccount.ResourceGroupName -AccountName $objStorageAccount.Id
if ($objAccountKey -ne $null)
{
here i should set the code for remove it
}
}
As you can see from the list of commands supported on azure storage module, there is no command to delete account key, Instead you can remove the container if you need or generate a new one from the portal.

Set a custom domain for a storage account using Azure Powershell

Is it possible to set up a custom domain for a Azure Resource Manager (ARM) storage account using Azure Powershell? If so, how?
I tried to set up a custom domain through the Azure Preview Web Portal but that functionality does not yet exist for the new resource manager storage accounts.
Using this documentation, I am able to login and see the properties of my new RM storage account, but I am unsure how to update the CustomDomain property. I expected to find an example/documentation of how this worked with the old storage accounts, but I have not found anything.
I have found a solution that worked for us. You can use the Set-AzureRmStorageAccount command to set properties on an existing storage group. Not sure how I missed this one.
Set-AzureRmStorageAccount -ResourceGroupName "<YOUR RESOURCE GROUPNAME>" -Name "<YOUR STORAGE ACCOUNT NAME>" -CustomDomainName <YOUR.CUSTOM.DOMAIN> -UseSubDomain $true
In case, like me, you get ResourceGroupNotFound do following command to select your subscription before (you get your subscription id in the Azure Portal):
Select-AzureRmSubscription -SubscriptionId <YourSubscriptionID>

Resources