How to login from an Azure Resource Manager Runbook? - powershell

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.

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 Runbooks, Connect-AzAccount, Assigning rights

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

Trying to Log in to Azure in Powershell

I am following the MS guide located here and everything goes through correctly until I have to actually log in. The pop up window appears for my creds and validates them, but powershell doesn't seem to notice.
So it goes Install Module, Import Module, Verify Version, Log in. See below for what happens on the last two steps.
PS C:\WINDOWS\system32> Get-Module AzureRM -ListAvailable | Select-Object -Property Name,Version,Path
Name Version Path
---- ------- ----
AzureRM 6.3.0 C:\Program Files\WindowsPowerShell\Modules\AzureRM\6.3.0\AzureRM.psd1
PS C:\WINDOWS\system32> Connect-AzureRmAccount
Account :
SubscriptionName :
SubscriptionId :
TenantId :
Environment :
PS C:\WINDOWS\system32>
Of course, this prevents me from doing very much else with Azure from that point forward.
Edit: Issue appears on multiple workstations
I got this same issue. I have two users like many of you: the Azure user that is the "Work" account, and then the "Personal" account which is also created automatically by Office365 and Azure. I was getting the issue when I tried to use my "personal" account, in which I have some subscriptions added (delegated).
After trying lots, what worked for me was to login to the "Work" account when the "Connect-AzureRmAccount" command asks for an username/password. Then, I again use the command "Connect-AzureRMAccount", but this time I entered the personal account, and it finally worked.
Picture here
Edit: A better way I found later was this, as I manage a lot of subscriptions/tenants from a single account (delegated access):
Put the “tenantid” into a variable (you can get this ID on the Azure Portal, in my case, on the option to change directories):
How to get your tenant's IDs quickly
$tenantId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
Login specifying the TenantId:
Login-AzureRmAccount -TenantId $tenantId
Example 2
This behavior happens when you run
Clear-AzureRMContext -Scope CurrentUser
I'm not sure why and im attempting to debug on how to fix the issue. A work around is to close the powershell window and reopen a new powershell windows that does not have this command ran.
Running the command
Enable-AzureRmContextAutosave -Scope CurrentUser
Fixed the issue for me. This will autosave your context for every powershell session. If this is not desired you can run the command
Enable-AzureRmContextAutosave -Scope Process
which will save the azure context for only the process. Otherwise you will need to handle
You can try this...
Install-Module PoweshellGet -Force
Set-ExecutionPolicy -ExicutionPolicy Remotesigned
Install-Module AzureRm
Import-Module -Name AzureRm
Login-AzureRmAccount
You can use the below link to install latest PowerShell version:
https://github.com/Azure/azure-powershell/releases
And then use something like this in order to automatically pass in the username password, and skipping the UI:
$azureAccountName ="enter username here"
$azurePassword = ConvertTo-SecureString "password here" -AsPlainText -Force
$psCred = New-Object System.Management.Automation.PSCredential($azureAccountName, $azurePassword)
Login-AzureRmAccount -Credential $psCred
Have you tried the following:
Import-Module Microsoft.Powershell.Security
$azureAccountName ="enter username here"
$azurePassword = ConvertTo-SecureString "password here" -AsPlainText -Force
$psCred = New-Object System.Management.Automation.PSCredential($azureAccountName, $azurePassword)
$decrypt = $psCred.GetNetworkCredential()
$ptpass = $decrypt.Password
Write-Output "Logging in to Azure using $azureAccountName with a password of $ptpass"
Login-AzureRmAccount -Credential $psCred
If you receive an error with this code, please comment with the entire error message.
The only thing i can think of is the below
You maybe using Azure Service Management (Azure V1 / Azure Classic) which uses a different module to Azure Resource Manager (ARM , Azure V2).
To install Azure Service Management Module:
Install-Module Azure -AllowClobber
Allowing clobber because you already have AzureRM Module installed
Import Azure Module to PowerShell:
Import-Module Azure
Logs into ASM:
Add-AzureAccount
Shows you all subscriptions
Get-AzureSubscriptions
Selects the Subscription you allocate to work within
Select-AzureSubscription
Answered something similar in the below Thread:
Login-AzureRmAccount return subscription but Get-AzureSubscription return empty
Hope this helps
You can try logging in using the Service Principal credentials.
Service principal is an application created under Active Directory to which you can apply permission rules.
$pscredential = Get-Credential
Connect-AzureRmAccount -ServicePrincipal -ApplicationId "http://my-app" -Credential $pscredential -TenantId $tenantid
Refer here for more details.

Azure Provisioning - Without manual login

I have a Powershell script which runs to set up Azure web apps, databases, etc. but before running the script, I have to do the following:
PS C:/> Login-AzureRmAccount
This pops up a GUI in which I have to manually add in my user, password, and my 2-factor authentication code. I eventually want to use that script as a part of a part of a build/deployment automation script.
I gleaned the following from a few articles about using a "service principal".
First I do:
PS C:\> Add-AzureRmAccount
In this call I have to put in my user, password, and authentication code
After that I have to do the following (even though I don't fully understand).
$app = New-AzureRmADApplication -DisplayName "GGReal" -HomePage "https://www.example.org/ggreal" -IdentifierUris "https://www.example.org/ggreal" -Password "mysecretpass"
New-AzureRmADServicePrincipal -ApplicationId $app.ApplicationId
This seems to work:
Then I try this, and it fails.
New-AzureRmRoleAssignment -RoleDefinitionName Reader -ServicePrincipalName $app.ApplicationId
I got the following error:
New-AzureRmRoleAssignment : AuthorizationFailed: The client jay#myemail.com' with object id '8ee9a6ec-yyyy-xxxx-xxxx-4ac0883f2a12' does not have authorization to perform action 'Microsoft.Authorization/roleAssignments/write' over scope '/subscriptions/5ba06de5-xxxx-zzzz-yyyy-27f7d2c8bba6'.
At line:1 char:1
+ New-AzureRmRoleAssignment -RoleDefinitionName Reader -ServicePrincipa ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [New-AzureRmRoleAssignment], CloudException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.Resources.NewAzureRoleAssignmentCommand
What do I have to do to enable a scripted authorization without manual intervention?
According to the exception that it indicates that you don't has adequate permission to that. We can check active directory permissions following the document. Our account needs to have Microsoft.Authorization/*/Write access to assign an AD app to a role. That means our account should be assigned to the
Owner role or User Access Administrator role. If not, please ask your subscription administrator to add you to User Access Administrator role. How to add or change Azure administrator roles please refer to the document.
After that please have a try to Automate login for Azure Powershell scripts with the following code.
$azureAplicationId ="Azure AD Application Id"
$azureTenantId= "Your Tenant Id"
$azurePassword = ConvertTo-SecureString "strong password" -AsPlainText -Force
$psCred = New-Object System.Management.Automation.PSCredential($azureAplicationId , $azurePassword)
Add-AzureRmAccount -Credential $psCred -TenantId $azureTenantId  -ServicePrincipal
I also find some related documents about creating authentication and Built-in roles:
https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-authenticate-service-principal
https://learn.microsoft.com/en-us/azure/active-directory/role-based-access-built-in-roles#roles-in-azurel
Well, you don't have permissions to assign that role to that serviceprincipal, you need appropriate rights. And those would be: Microsoft.Authorization/roleAssignments/write and scope /subscriptions/5ba06de5-xxxx-zzzz-yyyy-27f7d2c8bba6
You could either create a new Custom Role and assign it to your account, or assign something like Subscription Admin (not sure if its the least possible approach, but you can retract it later) to your account.

Azure PowerShell automation "no default subscritpion has been designated"

I am getting the following error. I am in fact setting the default subscription name.
4/27/2015 10:28:28 AM, Error: Get-AzureVM : No default subscription
has been designated. Use Select-AzureSubscription -Default
to set the default subscription. At test:9 char:9
+
+ CategoryInfo : CloseError: (:) [Get-AzureVM], ApplicationException
+ FullyQualifiedErrorId : Microsoft.WindowsAzure.Commands.ServiceManagement.IaaS.GetAzureVMCommand
Here is my code:
workflow test
{
# Initial set up
$Cred = Get-AutomationPSCredential -Name "******"
Add-AzureAccount -Credential $Cred
Select-AzureSubscription -Default -SubscriptionName 'Beebunny'
$vmName = "MyMachineName"
Get-AzureVM -servicename $vmName
Write-output "All done."
}
If I try Select-AzureSubscription -Default 'SubscriptionName' it throws an error saying the syntax is invalid.
Edit: I have also tried Select-AzureSubscription -SubscriptionName 'SubscriptionName' without the Default flag.
Funny thing is that if I run this in AzurePS directly from Windows, it runs just fine. I am about 95% sure this is an Azure bug but wanted to get a second opinion first.
What version of the Azure module do you have loaded? Are you using the default module provided by the Automation service? Also, have you imported any other modules to this subscription?
Try creating a clean runbook with the following code, replacing the credential and subscription with the proper names. Can you get the credential and authenticate successfully?
workflow Test-GetVM
{
$Cred = Get-AutomationPSCredential -Name 'AdAzureCred'
if(!$Cred) {
Throw "Could not find an Automation Credential Asset named. Make sure you have created one in this Automation Account."
}
$Account = Add-AzureAccount -Credential $Cred
if(!$Account) {
Throw "Could not authenticate to Azure. Make sure the user name and password are correct."
}
Select-AzureSubscription -SubscriptionName "Visual Studio Ultimate with MSDN"
Get-AzureVM
}
UPDATE: Do you have the Resource Manager module loaded to the subscription as well?
I had the same problem and the solution was execute Add-AzureAccount, do the login process requested and once done all was working.