Azure Automation Runbooks, Connect-AzAccount, Assigning rights - powershell

I am trying to do some basic group management using Azure Automation, but I'm having a heck of a time getting the script to authenticate correctly.
I have added the Azure.Account modules to the runbook, and the connection seems to get established (at least, it doesn't throw an exception, and the returned object is not null).
When using "Get-AzAdGroup", I am getting:
Get-AzADGroup : Insufficient privileges to complete the operation.
The app account created is a "Contributor" in AAD, so as far as I understand, has full rights to the directory.
I have tried the solution listed at How to connect-azaccount in Azure DevOps release pipeline, to the same effect (Insufficient privileges). I have also applied "Group.Read.All", "Group.ReadWrite.All", "GroupMember.Read.All", "GroupMember.ReadWrite.All" based on what I can read from https://learn.microsoft.com/en-us/graph/permissions-reference#group-permissions - but I'm not 100% clear if the Az* cmdlets use the Microsoft Graph, or if that's separate altogether.
Code is as follows:
$connectionName = "AzureRunAsConnection"
try
{
# Get the connection "AzureRunAsConnection "
$servicePrincipalConnection=Get-AutomationConnection -Name $connectionName
"Logging in to Azure..."
<#
# Original, technically legacy.
Add-AzureRmAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
#>
$connectState = Connect-AzAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
<#
# From https://stackoverflow.com/questions/56350960/how-to-connect-azaccount-in-azure-devops-release-pipeline, same result.
$AzurePassword = ConvertTo-SecureString "*****" -AsPlainText -force
$psCred = New-Object System.Management.Automation.PSCredential($servicePrincipalConnection.ApplicationId , $AzurePassword)
$connectState = Connect-AzAccount -Credential $psCred -TenantId $servicePrincipalConnection.TenantId -ServicePrincipal
#>
if ($connectState) {
"Connected."
} else {
"Doesn't seem to be connected."
}
}
catch {
if (!$servicePrincipalConnection)
{
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
} else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}
# Get groups
Get-AzADGroup
My gut tells me that since both connect-azaccount methods yield the same result (connected, but no access) my issue isn't necessarily in the script, but short of creating a service account (which presents challenges with MFA), I don't know how to fix this.

From the solution How to connect-azaccount in Azure DevOps release pipeline I provided, in the screenshot, it is clear that you need to add the API permission of Azure Active Directory Graph, not Microsoft Graph.
Please add the Directory.Read.All in Azure Active Directory Graph for the AD App of your automation run as account.

I have faced a very similar issue. You have a problem with the API permissions Azure APP has.
In my case, my azure App was working as a Service Principal, and not only modifying some stuff in the Azure AD, but also some Azure resources, therefore, these were the api permissions that I had to grant:
Remember that you also need to grant admin consent from the Azure tenant for these permissions update.

If you just assign Contributor role to the service principal, you just can use the sp to get Azure resource(such as VM, app service). So if you want to use the sp tp get Azure AD resource, we need to assign Azure AD role (sucah as Directory Readers) to the sp. For more details, please refer to the document and the document
The detailed steps are as below
Get the RunAsAccount sp object id
Confugure Permisisons for the application
connect-AzureAD
$sp=Get-AzureADServicePrincipal -ObjectId <the sp object id your copy>
$role=Get-AzureADDirectoryRole | Where-Object{$_.DisplayName -eq "Directory Readers"}
Add-AzureADDirectoryRoleMember -ObjectId $role.ObjectId -RefObjectId $sp.ObjectId
Test
a. create a new runbook
$servicePrincipalConnection=Get-AutomationConnection -Name 'AzureRunAsConnection'
$connectState = Connect-AzAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
if ($connectState) {
"Connected."
} else {
"Doesn't seem to be connected."
}
Get-AzADGroup

Go to Azure portal --> Azure AD --> roles and Administrator-->Directory Readers role --> assign this role to the runbook account name

Related

Connect with teams from an Azure Automation with "run as" account

I would like to assign Teams policies from an Azure Automation. For this I use the PowerShell module "MicrosoftTeams" in the current version.
When I log in to Teams with user credential, as shown below, the assignment works.
$Cred = Get-AutomationPSCredential -Name 'Teams-Admin'
Connect-MicrosoftTeams -TenantId $tenantId -Credential $Cred
# Grant policys
Grant-CsUserPolicyPackage -Identity $mailAddress -PackageName Test
However, I want to use the Run-As account to log in, as shown below. When I do that, I get an error.
$connection = Get-AutomationConnection –Name AzureRunAsConnection
Connect-MicrosoftTeams -TenantId $connection.TenantID `
-ApplicationId $connection.ApplicationID `
-CertificateThumbprint $connection.CertificateThumbprint
# Grant policys
Grant-CsUserPolicyPackage -Identity $mailAddress -PackageName Test
The error is as follows:
Grant-CsUserPolicyPackage : Powershell administered domain is unexpectedly null/empty
The app registry of the "Run-As" account has the Teams administrator and Skype for Business administrator role. In addition, I have delegated "AppCatalog.ReadWrite.All", "Group.ReadWrite.All", "User.Read.All" permissions to Microsoft Graph in the API permissions and "user_impersonation" permissions to Skype and Teams Tenant Admin API.
Service Principal names is currently not supported. We have backlog item for this but do not have an ETA to share.

Azure Automation | Runbook | Powershell | Get-AzRoleAssignment | Microsoft.Rest.Azure.CloudException

I have an Automation account and I have set up the Run-As-Account for non-classic resources. In my automation Account I have imported Az.Resources, Az.Account, Az.Storage and Az.KeyVault.
I have a script that does not work under the Automation service principle. The following error is a first of 3;
Get-AzRoleAssignment : Exception of type 'Microsoft.Rest.Azure.CloudException' was thrown. At line:26 char:10
I have granted the application registration the following set of application api permissions in Azure Active Directory (more than I anticipate needing);
At the start of the script I run the Connect-AzAccount cmdlet;
$servicePrincipalConnection = Get-AutomationConnection -Name 'AzureRunAsConnection'
Connect-AzAccount -ServicePrincipal `
-Tenant $servicePrincipalConnection.TenantID `
-ApplicationId $servicePrincipalConnection.ApplicationID `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
Followed by the failing command;
If(!(Get-AzRoleAssignment | Where-Object { $_.RoleDefinitionName -eq "Storage Blob Data Contributor" `
-and $_.scope -eq "/subscriptions/$subscription/resourceGroups/$resourceGroup/providers/Microsoft.Storage/storageAccounts/$serviceName" `
-and $_.SignInName -eq (Get-AzContext).Account.Id})){
# There does not exist the requisite permission for the run-as-account context, grant; 'Storage Blob Data Contributor'.
New-AzRoleAssignment -RoleDefinitionName "Storage Blob Data Contributor" `
-ApplicationId (Get-AzADServicePrincipal | Where-Object { $_.DisplayName -eq "jupiterautomation01" }).ApplicationId `
-Scope "/subscriptions/$subscription/resourceGroups/$resourceGroup/providers/Microsoft.Storage/storageAccounts/$serviceName"
}
I need to grant the right permissions, but do not know what they are.
The permissions assigned need to be consented to by an 'admin'. The button was only available when accessing Azure via the Microsoft account used to create the Active Directory tenant.
Sign in with an admin account that can consent.
Grant API permissions to read or read/write (i needed write as well) on Active Directory to the application.
Give admin consent using the button displayed in the image.

Authentication_MissingOrMalformed when executing New-AzureADApplication

I'm trying to run this script but I get this error :
New-AzureADApplication : Error occurred while executing NewApplication
Code: Authentication_MissingOrMalformed
Message: Access Token missing or malformed.
Import-Module AzureAD  -Force
$rmAccount = Add-AzureRmAccount
$subscriptionId = $rmAccount.Context.Subscription.Id
$tenantId = $rmAccount.Context.Tenant.Id
$tokenCache = $rmAccount.Context.TokenCache
$cachedTokens = $tokenCache.ReadItems() `
| where { $_.TenantId -eq $tenantId } `
| Sort-Object -Property ExpiresOn -Descending
$infos = Connect-AzureAD -TenantId $tenantId `
-AadAccessToken $cachedTokens[0].AccessToken `
-AccountId $rmAccount.Context.Account.Id
$clientAadApplication = New-AzureADApplication -DisplayName "TodoListClient-NativeDotNet" `
-ReplyUrls "https://TodoListClient-NativeDotNet" `
-PublicClient $True
$currentAppId = $clientAadApplication.AppId
$clientServicePrincipal = New-AzureADServicePrincipal -AppId $currentAppId -Tags {WindowsAzureActiveDirectoryIntegratedApp}
$currentAppId = $clientAadApplication.AppIds
What I'm trying to do is to automatically register a native application in Azure Active Directory without dependency to Azure portal so I logged in using Add-AzureRmAccount to get TenantId and SubscriptionId then I used the cached token to connect to AzureAD to prevent double login.
The token that you obtain when you run Add-AzureRmAccount is for the https://management.core.windows.net audience, but Azure AD cmdlets need a token for Azure AD Graph audience (https://graph.windows.net). So you can't reuse that token while calling New-AzureADApplication. You should choose between Azure RM or Azure AD cmdlets, but not both. But as far as I know New-AzureRmADApplication doesn't support creating a native application, so then you should use only Azure AD cmdlets.
You were close, but the token you are passing from the AzureRMAccount is not the correct Audience/Resource for the actions you are doing. Just removing that bit and running something like this below will work with the correct Audience and Resource permissions for your Token. You can always check your Token Audience and scope by copying and pasting it at https://jwt.ms (a useful Token debugger by Microsoft).
Import-Module AzureAD -Force
Connect-AzureAD
$clientAadApplication = New-AzureADApplication -DisplayName "TodoListClient-NativeDotNet" `
-ReplyUrls "https://TodoListClient-NativeDotNet" `
-PublicClient $True
$currentAppId = $clientAadApplication.AppId
$clientServicePrincipal = New-AzureADServicePrincipal -AppId $currentAppId -Tags {WindowsAzureActiveDirectoryIntegratedApp}
$currentAppId = $clientAadApplication.AppIds

Azure Runbook Error, AzureRmStorageAccountKey Cannot Index into null array

I am trying to run this command within an Azure Run book
(Get-AzureRmStorageAccountKey -Name $defaultStorageAccountName -ResourceGroupName $defaultResourceGroupName).Value[0]
It runs fine on my local machine and I can see the Storage Account Key. However, when I run the same command in Azure Runbook it throws the following error
Cannot index into a null array
If I just run Get-AzureRmStorageAccountKey -Name $defaultStorageAccountName -ResourceGroupName $defaultResourceGroupName in the Azure Runbook, it runs fine and I can see the Keys. It is just when I am selecting an element from an Array that it fails and throws an error.
The PowerShell version is 5 on my local machine and on Azure Runbook.
Update:
My issue was resolved after updating the Modules from the Gallery in my automation account.
According to your description, I test your cmdlets in my runbook, I could get storage key.
You could use the following commands to login your subscriptions.
Write-Verbose "Get connection asset: $ConnectionAssetName" -Verbose
$connectionName = Get-AutomationConnection -Name "AzureRunAsConnection"
$AzureCredentialAssetName = "AzureRunAsConnection"
try
{
# Get the connection "AzureRunAsConnection "
$servicePrincipalConnection=Get-AutomationConnection -Name $AzureCredentialAssetName
"Logging in to Azure..."
Add-AzureRmAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
}
catch {
if (!$servicePrincipalConnection)
{
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
} else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}
$key=(Get-AzureRmStorageAccountKey -Name <storage account name> -ResourceGroupName <resource group name>).Value[0]
"The storage account key is $key"
More information please refer to this link.
Update
You need update Azure Storage account module version in automation account, then you could solve this issue.

How to login from an Azure Resource Manager Runbook?

Using the new Azure portal, I am trying to add a powershell runbook that will start a specific VM. This is not something that will be run in powershell from my PC, it will instead run as an ARM job. I can't seem to find a way to successfully login.
If running from my desktop in powershell I can just call Login-AzureRmAccount and it will launch a login dialog before running any further steps. From what I've read on the web it seemed that what I needed to do was add a credential to my automation account, retrieve it and then call the same Login method. I've now done that, but still can't log in.
Import-Module AzureRM.Compute
$AutomationCredentialAssetName = "automation"
$Cred = Get-AutomationPSCredential -Name $AutomationCredentialAssetName
Write-Output $Cred
Login-AzureRmAccount -Credential $Cred
Start-AzureRmVm -Name 'myvmname' -ResourceGroupName 'myresourcegroupname'
The credential is being retrieved correctly (get's written to output) but the call to the Login-AzureRmAccount fails with:
Login-AzureRmAccount : unknown_user_type: Unknown User Type
At line:10 char:1
+ Login-AzureRmAccount -Credential $Cred
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Add-AzureRmAccount], AadAuthenticationFailedException
+ FullyQualifiedErrorId : Microsoft.Azure.Common.Authentication.AadAuthenticationFailedException,Microsoft.Azure.Com
mands.Profile.AddAzureRMAccountCommand
If I don't attempt to log in first I get a message telling me to call Login-AzureRmAccount first.
How do I authenticate from within a runbook so that I can run automation tasks? What am I doing wrong?
We have subsequently discovered the the automation account created a connection when created that can be used to login:
$connectionName = "AzureRunAsConnection"
try
{
# Get the connection "AzureRunAsConnection "
$servicePrincipalConnection = Get-AutomationConnection -Name $connectionName
"Logging in to Azure..."
Add-AzureRmAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
}
catch {
if (!$servicePrincipalConnection)
{
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
} else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}
At a guess you are trying to log in with a Microsoft account, which can only be done interactively (as it needs to redirect through live.com). You will need to create a user within the tenant (Active Directory) that you are authenticating against in order for non-interactive login to work.
The easiest method to make this work is to create an account in the old portal (the new portal doesn't support Active Directory management yet) and then to add that user as a co-administrator in settings > administrators.
You can create a user through Powershell, and assign much more granular permissions, but while you're working your way around things it is probably easier to stay within the portal.
There is no significant difference between a user created through the old portal and one created via AzureRm commands.
I just encountered the same problem and while the information posted here was helpful it didn't solve the problem completely.
The key insight I needed was that in order to use Azure Cmdlets one has to configure a 'Run as Account'. (See https://learn.microsoft.com/en-us/azure/automation/automation-sec-configure-azure-runas-account)
It can be set up under Account Settings section of the azure automation account.
Once you have the 'Run as Account' you can use the method proposed by BlackSpy to log in. Namely:
# Get the connection
$servicePrincipalConnection = Get-AutomationConnection -Name AzureRunAsConnection
"Logging in to Azure..."
Add-AzureRmAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
Hope this might help someone.
The official advice is to use a ServicePrincipal for automation - you can either use Secret or Certificate credentials with a service principal, and certificates work the best.
It is still possible to use a work or school account for automated login (Login with just -Credential), but this requires that your organization does not require two-factor authentication. It is unfortunately not possible to use a Microsoft Account for this - microsoft accounts require user interaction for any login.