Use the AZ module in a non-interactive environment? - powershell

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

Related

I am getting the "Sequence contains no elements error" while running a build pipeline in Azure DevOps services to deploy a cloud service (classic)

I have created an Azure Classic type service connection. Is there anything I am missing?
I am then using this Azure Classic Service connection to deploy the cloud service to Azure.
Azure Deployment: D:\a\1\a\*.cspkg
View raw log
Starting: Azure Deployment: D:\a\1\a\*.cspkg
----------------------------------------------------------------
Task : Azure Cloud Service deployment
Description : Deploy an Azure Cloud Service
Version : 1.175.2
Author : Microsoft Corporation
Help : https://learn.microsoft.com/azure/devops/pipelines/tasks/deploy/azure-cloud-powershell-deployment
----------------------------------------------------------------
Import-Module -Name C:\Modules\azure_2.1.0\Azure\2.1.0\Azure.psd1 -Global
Import-Module -Name C:\Modules\azurerm_2.1.0\AzureRM\2.1.0\AzureRM.psd1 -Global
##[warning]The names of some imported commands from the module 'AzureRM.Websites' include unapproved verbs that might make them less discoverable. To find the commands with unapproved verbs, run the
Import-Module command again with the Verbose parameter. For a list of approved verbs, type Get-Verb.
Import-Module -Name C:\Modules\azurerm_2.1.0\AzureRM.Profile\2.1.0\AzureRM.Profile.psm1 -Global
Add-AzureAccount -Credential System.Management.Automation.PSCredential
##[error]Sequence contains no elements
-
##[error]There was an error with the Azure credentials used for the deployment.
-
Finishing: Azure Deployment: D:\a\1\a\*.cspkg
PS: I am using the classic editor to create the pipelines and not YAML builds.
##[error]There was an error with the Azure credentials used for the deployment.
You could change to use the Certificate Based as the verification method.
To use the Certificate Based method, you could use the following script to create the .cer file.
$cert = New-SelfSignedCertificate -DnsName yourdomain.cloudapp.net -CertStoreLocation "cert:\LocalMachine\My" -KeyLength 2048 -KeySpec "KeyExchange"
$password = ConvertTo-SecureString -String "your-password" -Force -AsPlainText
Export-PfxCertificate -Cert $cert -FilePath ".\my-cert-file.pfx" -Password $password
Export-Certificate -Type CERT -Cert $cert -FilePath .\my-cert-file.cer
Then you could get the upload certificate with the management portal.
At the same time , you could get the Public key with .cer file.
This key is used in the service connection.
You can refer to this ticket to get the possible cause of the problem
Through the following error message, the problem is obvious. Like this pic.
##[error]Sequence contains no elements
##[error]There was an error with the Azure credentials used for the deployment.
You need get $cred by below script.(There are some restriction, for more details, pls read related posts.)
$username = "**.com"
$password = "***"
$secstr = New-Object -TypeName System.Security.SecureString
$password.ToCharArray() | ForEach-Object {$secstr.AppendChar($_)}
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $secstr
Add-AzureRmAccount -Credential $cred
Related Posts
1. Visual Studio Team Services: Sequence contains no elements
2. Add-AzureRmAccount : Sequence contains no elements

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.

VSTS Build and PowerShell and AzureAD Authentication

I have a VSTS project connected via a Service Principal to an Azure subscription through an Azure Resource Manager endpoint. This works fine for my builds that configure ARM resources via templated, parameter driven deployments.
I have an additional requirement to set up Azure AD groups as part of the build. I have a script that works fine from my local machine. When I deployed it via the build and it executed on the hosted build controller, the script could initially not find the AzureAD module. I got around this by including the script in git Repo and accessing it through:
$adModulePath = $PSScriptRoot + "\PsModules\AzureAD\2.0.0.131\AzureAD.psd1"
Import-Module $adModulePath
However, I now have another problem when it comes to running New-AzureADGroup. The script requires Connect-AzureAD to be run before the command is issued. This works fine by hardcoding a credential but I don't want to do this, I want it to run under the context of the SPN created, which is running the scripts on the hosted build controller.
So, the question is, can I get the current context of the Azure PowerShell execution SPN and pass that to Connect-AzureAD to avoid storing credential in plain text? Am I missing a trick? Are there any alternatives?
My current code is as below, the commented connection works fine from the command like with hard coded values. The call with no parameters presents the login UI which terminates the build since it is obviously not interactive.
## Login to Azure
#$SecurePassword = ConvertTo-SecureString $AdminPassword -AsPlainText -Force
#$AdminCredential = New-Object System.Management.Automation.PSCredential ($AdminUserEmailAddress, $SecurePassword)
#Connect-AzureAD -Credential $AdminCredential
Connect-AzureAD
Write-Output "------------------ Start: Group Creation ------------------"
$TestForAdminGroup = Get-AzureADGroup -SearchString $AdminGroup
$TestForContributorGroup = Get-AzureADGroup -SearchString $ContributorGroup
$TestForReaderGroup = Get-AzureADGroup -SearchString $ReaderGroup
Thanks
This is possible. Got it working today for my own VSTS extension that I released a while ago. My extension is using a Azure Resource Manager endpoint as input.
Running it now on a Microsoft Hosted Visual Studio 2017 agent pool using the below code. See for more information my post on how to use AzureAD PowerShell cmdlets on VSTS agent.
Write-Verbose "Import AzureAD module because is not on default VSTS agent"
$azureAdModulePath = $PSScriptRoot + "\AzureAD\2.0.1.16\AzureAD.psd1"
Import-Module $azureAdModulePath
# Workaround to use AzureAD in this task. Get an access token and call Connect-AzureAD
$serviceNameInput = Get-VstsInput -Name ConnectedServiceNameSelector -Require
$serviceName = Get-VstsInput -Name $serviceNameInput -Require
$endPointRM = Get-VstsEndpoint -Name $serviceName -Require
$clientId = $endPointRM.Auth.Parameters.ServicePrincipalId
$clientSecret = $endPointRM.Auth.Parameters.ServicePrincipalKey
$tenantId = $endPointRM.Auth.Parameters.TenantId
$adTokenUrl = "https://login.microsoftonline.com/$tenantId/oauth2/token"
$resource = "https://graph.windows.net/"
$body = #{
grant_type = "client_credentials"
client_id = $clientId
client_secret = $clientSecret
resource = $resource
}
$response = Invoke-RestMethod -Method 'Post' -Uri $adTokenUrl -ContentType "application/x-www-form-urlencoded" -Body $body
$token = $response.access_token
Write-Verbose "Login to AzureAD with same application as endpoint"
Connect-AzureAD -AadAccessToken $token -AccountId $clientId -TenantId $tenantId
To conclude, the Powershell module can’t share the same context and you need to store the credential in secret variable in VSTS.
To take this further, it is possible to use the Service Principal by following example 3 here:
https://learn.microsoft.com/en-us/powershell/module/azuread/connect-azuread?view=azureadps-2.0
Once you have created a self-signed cert and attached it, you can connect to the Azure AD by passing in the thumbprint of the cert along with a couple of other parameters:
Connect-AzureAD -TenantId $tenantId -ApplicationId $sp.AppId -CertificateThumbprint $thumb

Azure Credentials for build server

I'm having authentication headaches with Azure. I have a continuous build server running powershell scripts, and I'm getting messages like:
Your Azure credentials have not been set up or have expired, please run Login-AzureRMAccount to set up your Azure credentials.
I don't like having to login with my account on the build server. I suppose I could create another account just for building, but that will expire as well. Is there a better way of handling this?
You should not use Login-AzureRmAccount in your build/deploy scripts because this is an interactive login, but rather Add-AzureRmAccount instead.
Add-AzureRmAccount requires you create a service principal (application) in Azure AD and use its client id and secret/key to authenticate.
Here is a code snippet that you can use:
$clientID = "<the client id of your AD Application>"
$key = "<the key of your AD Application>"
$SecurePassword = $key | ConvertTo-SecureString -AsPlainText -Force
$cred = new-object -typename System.Management.Automation.PSCredential `
-argumentlist $clientID, $SecurePassword
Add-AzureRmAccount -Credential $cred -Tenant "xxxx-xxxx-xxxx-xxxx" -ServicePrincipal
To find out you tenant id (single subscription)
$tenant = (Get-AzureRmSubscription).TenantId
Find tenant id (multiple subscriptions)
$tenant = (Get-AzureRmSubscription -SubscriptionName "My Subscription").TenantId

Azure Powershell programmatic login

I am working with Azure (HDInsight in particular) using a personal account (no work/school acocunt).
I would create a script that automatically login on azure and perform some actions.
I found a solutions saving an azure publishsetting json file after logging with our credentials but this settings file contains token that expires.
How can I deal with this issue? What is the best way to accomplish this automatico logon?
Thanks
Roberto
You need to create a service principal. Once you've created the service principal you can assign it permissions on specific resources using Role-Based Access Control. From there your script can login as the service principal without requiring you to login interactively.
The main concern with this approach is securing access to your script since it contains credentials that allow access to your Azure resources.
This article has a good walkthrough:
#First, login as yourself so you can setup the service principal
Login-AzureRmAccount
#Password doesn't have to be *your* password, but the password the script will use
$app = New-AzureRmADApplication –DisplayName "<Your script name>" –HomePage "http://localhost" –IdentifierUris "http://localhost/YourAppName" –Password "<Password>"
#Create the service principal
New-AzureRmADServicePrincipal –ApplicationId $app.ApplicationId
#Assign the Reader role to your new service principal. Other roles listed at
#https://azure.microsoft.com/en-us/documentation/articles/role-based-access-built-in-roles/
New-AzureRmRoleAssignment –RoleDefinitionName Reader –ServicePrincipalName $app.ApplicationId
$pass = ConvertTo-SecureString "<Password>" -AsPlainText –Force
#Servce principal username looks like 92c22f1f-d1d4-46a1-b025-edb47fc03809#something.onmicrosoft.com
#the GUID part is $app.ApplicationId and the domain part is found in the Azure portal
$cred = New-Object -TypeName pscredential –ArgumentList "<Service Principal UserName>", $pass
Login-AzureRmAccount -Credential $cred -ServicePrincipal –TenantId <TenantId>
If it is not a production/shared setup and more a developer setup you can also do, careful, the password is plain text here:
$SubscriptionName = 'MySubscription'
$pswd = 'MyPassword' | ConvertTo-SecureString -AsPlainText -Force
$creds = New-Credential -UserName 'MyEmail#something.com' -Password $pswd
Add-AzureRmAccount -Credential $creds
Set-AzureRmContext -SubscriptionName $SubscriptionName
Login-AzureRmAccount -Credential $creds -SubscriptionName $SubscriptionName
Below information might help you
Create an Automation Account in Azure
Add your credentials in Automation Account as a variable ( e.g
variablename = loginazure) Below Script will automatically login into azure (use Powershell workflow runbook).
$AzureLogin = Get-AutomationPSCredential -Name 'loginazure'
$AzurePortalLogin = New-Object -TypeName System.Management.Automation.PSCredential$AzureLogin
Add-AzureRmAccount -Credential $AzurePortalLogin
Get-AzureRmSubscription -SubscriptionName "your subscription name" | Set-AzureRmContext
use the above script within Inline Script {}
Regards
Thamarai Selvan S
Here are a couple of commands that you can fire up to get started.
$credentials = Get-Credential
Login-AzureRmAcoount -Credential $credentials
$SubscriptionName
Select-AzureRmSubscription -SubscriptionName "The name of your subscription"
Select-AzureRmSubscription -SubscriptionName $SubscriptionName