Make Azure Authentication Run Silently without Password Prompt - azure

I have a PowerShell script that connects to Azure, then downloads data. The script runs great with human interaction, but I'm trying to run it silently as a scheduled task. Currently, every time the script runs, it prompts for user credentials. I change 'Always' to 'Never' and it doesn't seem to store the credentials for any length of time.
$clientId = "<CLIENTIDHERE>" # PowerShell clientId
$redirectUri = "<REDIRECTURIHERE>"
$MSGraphURI = "https://graph.microsoft.com"
$authority = "https://login.microsoftonline.com/$tenantId"
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
$authResult = $authContext.AcquireToken($MSGraphURI, $clientId, $redirectUri, "Always")
$token = $authResult.AccessToken
Ideally the credentials would be passed through based on the credentials running in the scheduled task. If that isn't an option, at least I'm hoping to put the username and password in the script and have the script send those credentials to authenticate. How does one authenticate silently to Azure?

You could check the script shared by Bogdan Gavril from this thread .
#Require -Version 5.0
using namespace Microsoft.IdentityModel.Clients.ActiveDirectory
$adalDll = [Reflection.Assembly]::LoadFile("<path_to>\Microsoft.IdentityModel.Clients.ActiveDirectory.dll")
$ADAuthorityURL = "https://login.windows.net/common/oauth2/authorize/"
$resourceURL = "https://analysis.windows.net/powerbi/api"
$AADuserName = "foo"
$AADpassword = "bar"
Write-Host "Retrieving the AAD Credentials...";
$credential = New-Object UserPasswordCredential($AADuserName, $AADpassword);
$authenticationContext = New-Object AuthenticationContext($ADAuthorityURL);
$authenticationResult = [AuthenticationContextIntegratedAuthExtensions]::AcquireTokenAsync($authenticationContext, $resourceURL, $AADClientID, $credential).Result;
$ResultAAD = $authenticationResult.AccessToken;

I was able to figure this out. The initial authentication code I presented used an Azure-specific pop-up window to grab your credentials. Using the following link [1] I converted the code to the PowerShell Get-Credential method instead. From there, I used the information in this link [2] (Example 7) to configure the Get-Credential method to pull from plain text instead of a pop-up Window.
Now plain text passwords isn't ideal, but for our needs, it was good enough.
$clientId = "<CLIENTIDHERE>" # PowerShell clientId
$redirectUri = "REDIRECTURIHERE"
$MSGraphURI = "https://graph.microsoft.com"
$authority = "https://login.microsoftonline.com/$tenantId"
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
$User = "<USERNAMEHERE>"
$PWord = ConvertTo-SecureString -String "<PASSWORDHERE>" -AsPlainText -Force
$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, $PWord
$AADCredential = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.UserCredential" -ArgumentList $credential.UserName,$credential.Password
$authResult = $authContext.AcquireToken($MSGraphURI, $clientId, $AADCredential)
$token = $authResult.AccessToken
[1] https://blogs.technet.microsoft.com/cloudlojik/2017/09/05/using-powershell-to-connect-to-microsoft-graph-api/
[2] https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.security/get-credential?view=powershell-6

Related

Create more than one delegated permission in Azure application with PowerShell?

I am creating a script to create a new app registration within Azure.
So far, all is working well, I can create the app, create the service principal, set a secret and add a redirect uri.
The issue I face is that I can create a delegation permission for the application using the below function:
$graph = "00000003-0000-0000-c000-000000000000"
$sharePoint = "00000003-0000-0ff1-ce00-000000000000"
$userRead = "e1fe6dd8-ba31-4d61-89e7-88639da4683d"
$myFilesWrite = "2cfdc887-d7b4-4798-9b33-3d98d6b95dd2"
$allSitesWrite = "640ddd16-e5b7-4d71-9690-3f4022699ee7"
Function SetPermissions($resourceId, $argument)
{
$rra = New-Object -TypeName "Microsoft.Open.AzureAD.Model.RequiredResourceAccess"
$rra.ResourceAppId = $resourceId
$rra.ResourceAccess = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList $argument ,"Scope"
Set-AzureADApplication -ObjectId $myApp.ObjectId -RequiredResourceAccess $rra
}
SetPermissions $graph $userRead
but I will need three permissions for my app - when I call the function a second time it just overwrites the existing permission rather than adding a new one.
Any advice on how I can create multiple app permissions?
I tried to reproduce the same in my environment and got below results.
When I ran the same code as you, User.Read permission is added to the application like below:
Now I changed the arguments and ran the code again as below:
$myApp = Get-AzureADApplication -SearchString MyApp
$graph = "00000003-0000-0000-c000-000000000000"
$sharePoint = "00000003-0000-0ff1-ce00-000000000000"
$userRead = "e1fe6dd8-ba31-4d61-89e7-88639da4683d"
$myFilesWrite = "2cfdc887-d7b4-4798-9b33-3d98d6b95dd2"
$allSitesWrite = "640ddd16-e5b7-4d71-9690-3f4022699ee7"
Function SetPermissions($resourceId, $argument)
{
$rra = New-Object -TypeName "Microsoft.Open.AzureAD.Model.RequiredResourceAccess"
$rra.ResourceAppId = $resourceId
$rra.ResourceAccess = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList $argument ,"Scope"
Set-AzureADApplication -ObjectId $myApp.ObjectId -RequiredResourceAccess $rra
}
SetPermissions $sharePoint $allSitesWrite //Changed this
Response:
When I checked the same in Portal, existing permission removed, and new permission added like below:
To add multiple delegated permissions to Azure AD application from PowerShell, you can make use of below script:
$Graph = New-Object -TypeName "Microsoft.Open.AzureAD.Model.RequiredResourceAccess"
$Graph.ResourceAppId = "00000003-0000-0000-c000-000000000000"
$SharePoint = New-Object -TypeName "Microsoft.Open.AzureAD.Model.RequiredResourceAccess"
$SharePoint.ResourceAppId = "00000003-0000-0ff1-ce00-000000000000"
$userRead = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "e1fe6dd8-ba31-4d61-89e7-88639da4683d","Scope"
$myFilesWrite = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "2cfdc887-d7b4-4798-9b33-3d98d6b95dd2","Scope"
$allSitesWrite = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "640ddd16-e5b7-4d71-9690-3f4022699ee7","Scope"
$Graph.ResourceAccess = $userRead
$SharePoint.ResourceAccess = $myFilesWrite, $allSitesWrite
$myApp = Get-AzureADApplication -SearchString MyApp
Set-AzureADApplication -ObjectId $myApp.ObjectId -RequiredResourceAccess $Graph, $SharePoint
Response:
When I checked the same in Portal, multiple delegated permissions added to the application successfully like below:
Reference:
How to assign Permissions to Azure AD App by using PowerShell by rajaniesh

Get-PnPTenantSite : Attempted to perform an unauthorized operation

Currently we get an access token and then pass this token to PowerShell script to loop across all ODFB personal sites.
$url = "https://XXXXX-admin.sharepoint.com"
$conn = Connect-PnPOnline -Url $url -AccessToken $access_token -ReturnConnection
$sitecollections = Get-PnPTenantSite -IncludeOneDriveSites:$true -Filter "Url -like '-my.sharepoint.com/personal/'" -Connection $conn | Select-Object -ExpandProperty Url
foreach ($site in $sitecollections)
{
....
}
It worked successfully for years until it was broken a while ago.
I tried different versions of PnP PowerShell:
PnP version
Error
SharePointPnPPowerShellOnline 3.21.2005.2 (currently used)
Get-PnPTenantSite : Attempted to perform an unauthorized operation.
SharePointPnPPowerShellOnline 3.29.2101.0
Get-PnPTenantSite : The current connection holds no SharePoint context.
PnP.PowerShell 1.10.28
Get-PnPTenantSite : Attempted to perform an unauthorized operation.
If I change script to use an user/password instead the access token, the script works without problems:
$url = "https://XXXXX-admin.sharepoint.com"
$User = "admin#mydomain.com"
$PWord = ConvertTo-SecureString -String "Password" -AsPlainText -Force
$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, $PWord
$conn = Connect-PnPOnline -Url $url -Credentials $Credential -ReturnConnection
$sitecollections = Get-PnPTenantSite -IncludeOneDriveSites:$true -Filter "Url -like '-my.sharepoint.com/personal/'" -Connection $conn | Select-Object -ExpandProperty Url
foreach ($site in $sitecollections)
{
....
}
So the error happens when the script connects to SP Online using an access token.
Perhaps the some things were changed. But what exactly? Have some scope to be added when an access token is requested?
Or have some new permissions to be added for the application in Azure AD?
Update:
Modified the script (added Write-Output "Connection is:" $conn | fl) to provide more details about connection and got the difference in ConnectionType property when SharePointPnPPowerShellOnline 3.21.2005.2 is used:
When an access token is used (and the script doesn't work properly), ConnectionType : O365
When an access token is used (and the script works fine), ConnectionType : TenantAdmin

AzureAD - ConditionalAccessPolicy PersistentBrowser error

I have the following script to create a Conditional Access policy but i get below error.
And i dont understand what is wrong
$conditions = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessConditionSet
$conditions.Applications = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessApplicationCondition
$conditions.Applications.IncludeApplications = "Office365"
$conditions.Users = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessUserCondition
$conditions.Users.IncludeRoles = #('62e90394-69f5-4237-9190-012177145e10', 'f28a1f50-f6e7-4571-818b-6a12f2af6b6c', '29232cdf-9323-42fd-ade2-1d097af3e4de', 'b1be1c3e-b65d-4f19-8427-f6fa0d97feb9', '194ae4cb-b126-40b2-bd5b-6091b380977d', '729827e3-9c14-49f7-bb1b-9608f156bbb8', '966707d0-3269-4727-9be2-8c3a10f19b9d', 'b0f54661-2d74-4c50-afa3-1ec803f12efe', 'fe930be7-5e62-47db-91af-98c3a49a38b1')
$conditions.Users.ExcludeGroups = $ExcludeCAGroup.ObjectId
$conditions.ClientAppTypes = #('Browser', 'MobileAppsAndDesktopClients')
$controls = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessGrantControls
$controls._Operator = "OR"
$controls.BuiltInControls = "MFA"
$session = New-Object -TypeName Microsoft.Open.MSGraph.Model.conditionalAccessSessionControls
$sessioncontrols = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessSignInFrequency
$sessioncontrols.Type = "days"
$sessioncontrols.Value = 30
$sessioncontrols.IsEnabled = $true
$session.SignInFrequency = $sessioncontrols
$persistent = New-Object -TypeName Microsoft.Open.MSGraph.Model.ConditionalAccessPersistentBrowser
$persistent.IsEnabled = $true
$persistent.Mode = "never"
$session.PersistentBrowser = $persistent
New-AzureADMSConditionalAccessPolicy -DisplayName "GRANT: Require MFA for Admin users and never persistent sessions" -State "Disabled" -Conditions $conditions -GrantControls $controls -SessionControls $session
The error i get is
New-AzureADMSConditionalAccessPolicy : Error occurred while executing NewAzureADMSConditionalAccessPolicy
Code: BadRequest
Message: 1032: ConditionalActionPolicy validation failed due to InvalidConditionsForPersistentBrowserSessionMode.
anyone have any ideas?
I have tried in my environment and got the same error like below:
If you are including persistent browser mode in your script, then make sure to select All applications for session control as mentioned in this MsDoc.
By Changing the IncludeApplications from office365 to All like below:
$conditions.Applications.IncludeApplications = "All"
I was able to create conditional access policy successfully :
I also tried keeping included app as office365,but changed $persistent.IsEnabled=$false .This worked maybe because it can only be enabled for all apps as suggested in the MsDoc.

How to get TenantId of Connect-AzureAD from PowerShell Script running in Azure function (Dotnet Core)?

I am trying to get TenantId from Connect-AzureAD that will be returned in the powershell script.
Below is the powershell script:
Install-Module -Name AzureAD
$User = "test#domain.onmicrosoft.com"
$PWord = ConvertTo-SecureString -String "password" -AsPlainText -Force
$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, $PWord
$context = Connect-AzureAD -Credential $credential
$tenantId = $context.TenantId.Guid.ToString()
[pscustomobject]#{
user = $tenantId
}
The script works when executed as a PowerShell script alone. But when, I try to run in dotnet core, it seems to be empty.
public static string RunScript()
{
using (Runspace myRunSpace = RunspaceFactory.CreateRunspace())
{
myRunSpace.Open();
using (PowerShell ps = PowerShell.Create())
{
var imagePath = Path.Combine(Environment.CurrentDirectory, #"Resources", "ConnectAzureAD.ps1");
string content = File.ReadAllText(imagePath);
ps.AddScript(content);
var piplineObjs = ps.Invoke();
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine(piplineObjs.Count.ToString());
foreach (PSObject obj in piplineObjs)
{
stringBuilder.AppendLine(obj.Properties["user"].Value.ToString());
}
return stringBuilder.ToString();
}
}
}
I get the following error:
System.Private.CoreLib: Exception while executing function: Object reference not set to an instance of an object.
The above function is invoked from a Azure Function. It is using Microsoft.PowerShell.SDK v6.2.7 and System.Management.Automation v6.2.7.
How can I get the tenant Id returned from powershell script in dotnet core?
Or how can I get tenant Id using code with just user's email and password?
Thank you!
You can get tenant id by request this graph api: https://graph.microsoft.com/v1.0/organization
In the response is of the api, we can find the id(which is the tenant id) in it:

AcquireTokenAsyn in Azure cloud shell

I'm trying to make some graph API calls from AZure CloudShell. To make the API call I have to acquire a token. I have a 100% working code in Azure Desktop version (PSVersion 5.1)
But same code not working in CloudShell, which runs s with (Core - 6.2)
Cloudshell libraries have couple of mismatches with documentations
Im trying to use this version of AcuireTokenAsync.
For which I have to initial PlatmforParameter
but when Im getting an error
$platformParameters = New-Object
"Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformParameters"
"Auto" New-Object : Cannot find an overload for "PlatformParameters"
and the argument count: "1". At line:1 char:23
+ ... arameters = New-Object "Microsoft.IdentityModel.Clients.ActiveDirecto ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [New-Object], MethodException
+ FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
Seems PlatformParameters accepting no arg constructor
This is my working code in Powershell Desktop 5.1 version
$clientId = "1950a258-227b-4e31-a9cf-717495945fc2" # well-known client ID for AzurePowerShell
$redirectUri = "urn:ietf:wg:oauth:2.0:oob" # redirect URI for Azure PowerShell
$resourceAppIdURI = "https://graph.windows.net"
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
$platformParameters = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformParameters" -ArgumentList 'Auto'
$authResultTask = $authContext.AcquireTokenAsync($resourceAppIdURI, $clientId, $redirectUri, $platformParameters)
$authResultTask.Wait()
$authResult = $authResultTask.Result
But same code doesn't work in CloudShell
Is there any well known variation of acquiring token from Azure Cloud shell
I wanted to automate the application creation and configuration via powershell script
As mentioned in the comment, no need to call the MS Graph APIs manually, you can automate them via AzureAD powershell module, which is also available in the cloud shell.
Samples:
1.Create application - New-AzureADApplication
New-AzureADApplication -DisplayName "My new application" -IdentifierUris "http://mynewapp.contoso.com"
2.Update an application - Set-AzureADApplication
For example, set the API permissions for the application.
$req = New-Object -TypeName "Microsoft.Open.AzureAD.Model.RequiredResourceAccess"
$acc1 = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "311a71cc-e848-46a1-bdf8-97ff7156d8e6","Scope"
$acc2 = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "aaff0dfd-0295-48b6-a5cc-9f465bc87928","Role"
$req.ResourceAccess = $acc1,$acc2
$req.ResourceAppId = "00000002-0000-0000-c000-000000000000"
$reqe = New-Object -TypeName "Microsoft.Open.AzureAD.Model.RequiredResourceAccess"
$acc1e = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "ddb3ca45-a192-477d-acb2-46bf9dc586de","Scope"
$acc2e = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "28379fa9-8596-4fd9-869e-cb60a93b5d84","Role"
$reqe.ResourceAccess = $acc1e,$acc2e
$reqe.ResourceAppId = "00000009-0000-0000-c000-000000000000"
Set-AzureADApplication -ObjectId <ObjectId> -RequiredResourceAccess #($req,$reqe)
I test the script in local and cloud shell, both work fine. If you have other requirements, just look into the Azure AD PowerShell doc, you can do most things related to AAD via this module.
For more details about the sample, you could refer to the two links, 1 and 2.

Resources