Connect-ExchangeOnline UnAuthorized - powershell

I'm working on updating our PowerShell scripts to use more secure connection methods. When I try, I get an error that says "UnAuthorized"
PS X:> Connect-ExchangeOnline -AppId $clientId -CertificateThumbprint $thumbPrint -Organization $organization UnAuthorized
At C:\Program
Files\WindowsPowerShell\Modules\ExchangeOnlineManagement\3.0.0\netFramework\ExchangeOnlineManagement.psm1:730 char:21
throw $_.Exception;
CategoryInfo : OperationStopped: (:) [], UnauthorizedAccessException
FullyQualifiedErrorId : UnAuthorized
Is what I highlighted in the following screenshot what I'm supposed to use for the organization parameter?
[snip]
How do I fix the UnAuthorized error?
Thanks

I agree with #scottwtang, you will get unauthorized error if your application don't have required roles and permissions.
I tried to reproduce the same in my environment and got below results:
I used below script from your previous question to generate certificate:
$CN = "GraphApp"
$cert=New-SelfSignedCertificate -Subject "CN=$CN" -CertStoreLocation "Cert:\CurrentUser\My" -KeyExportPolicy Exportable -KeySpec Signature -NotAfter (Get-Date).AddYears(5)
$Thumbprint = $Cert.Thumbprint
Get-ChildItem Cert:\CurrentUser\my\$Thumbprint | Export-Certificate -FilePath $env:USERPROFILE\Downloads\GraphApp.cer
Write-Output "$Thumbprint <- Copy/paste this (save it)"
Output:
Now I uploaded this certificate to Azure AD application like below:
For $organization parameter, you need to pass your domain name. You can find that here:
Go to Azure Portal -> Azure Active Directory -> Overview -> Primary domain
When I ran the below script to connect Exchange Online, I got Access denied error like this:
$clientId="47xxxd8-8x2x-4xxx-bxx7-30cxxxxx8"
$thumbPrint="E4A0F6C6B85EBFxxxxxCD91B5803F88E5"
$organization="xxxxxxxx.onmicrosoft.com"
Connect-ExchangeOnline -AppId $clientId -CertificateThumbprint $thumbPrint -Organization $organization
Output:
To resolve the error, you need to add API permission and Directory role to your application:
Make sure to grant admin consent for the added permission as below:
Now I added Exchange Administrator role to my application like below:
Go to Azure Portal -> Azure Active Directory -> Roles and administrators -> Exchange administrator -> Add assignment
It may take few minutes to assign role successfully as below:
Now I connected to Exchange Online by running script again and ran sample command Get-EXOMailbox -PropertySets Archive to verify it and got response successfully like below:
$clientId="47xxxd8-8x2x-4xxx-bxx7-30cxxxxx8"
$thumbPrint="E4A0F6C6B85EBFxxxxxCD91B5803F88E5"
$organization="xxxxxxxx.onmicrosoft.com"
Connect-ExchangeOnline -AppId $clientId -CertificateThumbprint $thumbPrint -Organization $organization
Output:
So, make sure to assign required roles and permissions for your application to fix the error.

Unfortunately Exchange.ManageAsApp no longer appears in the Graph API Permissions, so cannot be directly selected in the portal. But you can add the permission by adding the following to the JSON in the Manifest:
{
"resourceAppId": "00000002-0000-0ff1-ce00-000000000000",
"resourceAccess": [
{
"id": "dc50a0fb-09a3-484d-be87-e023b12c6440",
"type": "Role"
}
]
}

Related

Use the AZ module in a non-interactive environment?

I'm hoping to be able to use the Az module to retrieve a secret from an Azure key vault, for use with a PowerShell script that has been deployed to a server and is run daily by Windows Task Scheduler.
Initially, I needed to follow the oauth (a guess) process:
Connect-AzAccount -Tenant '69a29f45-...'
Which redirects to https://login.microsoftonline.com/..., asking you to choose an account:
eventually, it indicates success:
Authentication complete. You can return to the application. Feel free to close this browser tab.
After this has been completed, the script that retrieves the secret works as expected:
...
$AccessToken = Get-AzKeyVaultSecret -VaultName 'MyVault' -Name 'MySecret' | Select-Object -ExpandProperty SecretValue | ConvertFrom-SecureString -AsPlainText
...
I'm concerned that the token will expire, causing my script to fail.
The SharePoint module (Pnp.PowerShell) can make use of a credential stored in Windows Credential Manager. Can the Az module do so as well?
If not, is there another way to handle this authentication process without interaction?
You can logon using a certificate tied to a Service Principal (SP) in your AD tenant. Then you just have to make sure that the SP has access to your key vault as at least a reader.
Looks we could not use Az module with the Windows Credential Manager, to use Az powershell in a non-interactive way, we always use a service principal, please follow the steps below.
1.Register an application with Azure AD and create a service principal.
2.Get values for signing in and create a new application secret.
3.Then use the commands below.
Note: Don't forget to add the service principal to the Access policies with the secret permission of the keyvault in the portal first.
$azureAplicationId ="<application-id>"
$azureTenantId= "<tenant-id>"
$azurePassword = ConvertTo-SecureString "<client-secret>" -AsPlainText -Force
$psCred = New-Object System.Management.Automation.PSCredential($azureAplicationId , $azurePassword)
Connect-AzAccount -Credential $psCred -TenantId $azureTenantId -ServicePrincipal
#get the secret
$AccessToken = Get-AzKeyVaultSecret -VaultName 'MyVault' -Name 'MySecret' | Select-Object -ExpandProperty SecretValue | ConvertFrom-SecureString -AsPlainText

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 functions & Powershell - unable to Login-AzureRmAccount using certificate

I'm building an Azure Function (hosted in app service plan) which will enumerate the assets in my subscription and do something with them.
I have the site set up in such a way that I expect it to work, but Login-AzureRmAccount errors out every time with the notice
Login-AzureRmAccount : No certificate was found in the certificate store with thumbprint xxxxxxxx
Here are some relevant pieces:
First I create the cert:
$cert = New-SelfSignedCertificate -CertStoreLocation cert:\currentuser\my -Subject "cn=$appCommonName" ...etc...
$keyValue = [System.Convert]::ToBase64String($cert.GetRawCertData())
$aNewApp = New-AzureRmADApplication -DisplayName $AzureADApplicationName -HomePage $AppHomePage -IdentifierUris $appIDUri -CertValue $keyValue -EndDate $cert.NotAfter -StartDate $cert.NotBefore
#export the cert for use future upload to Azure
$password = ConvertTo-SecureString -String "supersecrettpassword" -Force -AsPlainText
Export-PfxCertificate -Cert $cert -FilePath "Export-cert.pfx" -Password $password
Export-Certificate -Type CERT -Cert $cert -FilePath "Export-cert.cer"
Later I provision my Service Principal and give it read access
$theSvcPrincipal = New-AzureRmADServicePrincipal -ApplicationId $ApplicationId
$testRole = Get-AzureRmRoleAssignment -RoleDefinitionName Reader -ServicePrincipalName $ApplicationId
Through the magic of ARM deployments I end up with two app settings in the web site which hosts the azure function : WEBSITE_LOAD_CERTIFICATES with a value of * and CertThumbprint with a value of the thumbprint of the certificate which I've uploaded the the SSL certificates area.
Finally, after the ARM template is deployed, I upload the certificate following the instructions from this Stack Overflow post
Given all that prep work, I would expect this to work in my function:
Login-AzureRmAccount -ServicePrincipal -CertificateThumbprint $env:CertThumbprint -ApplicationId $env:ApplicationId -TenantId $env:TenantId
but when that line executes, despite my having a certificate in the web site with matching thumbprint, I get the no cert found wiht matching thumbprint error.
Ok, this was a bit embarrassing. It turns out that the ARM template I was using to provision the App Service was using the Dynamic sku:
"properties": {
"name": "[parameters('hostingPlanName')]",
"computeMode": "Dynamic",
"sku": "Dynamic"
}
rather than a standard sku:
"sku": {
"name": "B1",
"tier": "Basic",
"size": "B1",
"family": "B",
"capacity": 1
},
Once I switched the two, I was able to access the cert store.
I had seen this issue discussed on github, but dismissed it when a coworker was able to access a client certificate from a function app hosted on a dynamic plan after using the Azure web interface to provision it. I still can't explain how he was able to do it, but I've seen it with my own eyes and poured over the ARM templates from his deployment to verify that he's using the consumption-based model.

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.

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.