Azure Automation: Service Principal account from different tenant authenticates but doesn't return service principal - azure

I'm having issues executing a runbook aon a subscription in a different tenant.
This is what I have done so far:
1) Created a keyvault cert.
2) Exported .cer and .PFX of certificate.
3) Created a Service Principal on the rpgorch-aad account (300eab96-4619-4b6b-af42-8eb66506ab04)
4) Created a connection in Automation with that service principal's information
5) Uploaded password protected PFX to Automation certificate store
First, a working example from within the same tenant:
$connectionName = 'AzureRunasConnection'
"Getting Azure Connection $connectionName"
$servicePrincipalConnection = Get-AutomationConnection -Name $connectionName
"Logging in to Azure using Add-AzureRmAccount"
Add-AzureRmAccount -ServicePrincipal `
-Tenant $servicePrincipalConnection.TenantID `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint -Verbose
"Setting Context with Set-AzureRmContext"
Set-AzureRmContext -Tenant $servicePrincipalConnection.TenantID -SubscriptionId $servicePrincipalConnection.SubscriptionId -Verbose
"Writing Output of the Service Principal Connection"
write-output $servicePrincipalConnection
"Testing getting resource groups."
Get-AzureRmResourceGroup
Results:
Getting Azure Connection AzureRunasConnection
Logging in to Azure using Add-AzureRmAccount
PSComputerName : localhost
PSSourceJobInstanceId : Redacted
Environments : {AzureCloud, AzureChinaCloud, AzureUSGovernment}
Context : Microsoft.Azure.Commands.Profile.Models.PSAzureContext
Setting Context with Set-AzureRmContext
PSComputerName : localhost
PSSourceJobInstanceId : Redacted
Account : Redacted
Environment : AzureCloud
Subscription : Redacted
Tenant : Redacted
Writing Output of the Service Principal Connection
Name Value
---- -----
SubscriptionId Redacted
TenantId Redacted
ApplicationId Redacted
CertificateThumbprint Redacted
Testing getting resource groups.
PSComputerName : localhost
PSSourceJobInstanceId : Redacted
ResourceGroupName : Redacted
Location : eastus
Resources :
ResourcesTable :
ProvisioningState : Succeeded
Tags : {}
TagsTable :
ResourceId : /subscriptions/Redacted/resourceGroups/Redacted
Now the SAME code, but for the other tenant.
$connectionName = 'Redacted'
"Getting Azure Connection"
$connectionName
$Conn = Get-AutomationConnection -Name $connectionName
"Logging in to Azure using Add-AzureRmAccount"
Add-AzureRmAccount -ServicePrincipal `
-Tenant $Conn.TenantID `
-ApplicationId $Conn.ApplicationId `
-CertificateThumbprint $Conn.CertificateThumbprint -Verbose
"Setting Context with Set-AzureRmContext"
Set-AzureRmContext -Tenant $Conn.TenantID -SubscriptionId $Conn.SubscriptionId -Verbose
"Selecting subscriptionID "
$Conn.SubscriptionID
Select-AzureSubscription -SubscriptionId $Conn.SubscriptionID
"Testing getting resource groups."
Get-AzureRmResourceGroup
Results:
Getting Azure Connection
RPGOrchResourceManagement
Logging in to Azure using Add-AzureRmAccount
Results:
PSComputerName : localhost
PSSourceJobInstanceId : Redacted
Environments : {AzureCloud, AzureChinaCloud, AzureUSGovernment}
Context : Microsoft.Azure.Commands.Profile.Models.PSAzureContext
Setting Context with Set-AzureRmContext
Set-AzureRmContext : Provided subscription Redacted does not exist
At ManageSingleVM:52 char:52
+
+ CategoryInfo : CloseError: (:) [Set-AzureRmContext], ArgumentException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.Profile.SetAzureRMContextCommand
PSComputerName : localhost
PSSourceJobInstanceId : Redacted
Environments : {AzureCloud, AzureChinaCloud, AzureUSGovernment}
Context : Microsoft.Azure.Commands.Profile.Models.PSAzureContext
Setting Context with Set-AzureRmContext
Set-AzureRmContext : Provided subscription Redacted does not exist
At ManageSingleVM:52 char:52
+
+ CategoryInfo : CloseError: (:) [Set-AzureRmContext], ArgumentException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.Profile.SetAzureRMContextCommand

I figured out the answer to this. For anyone else looking, I needed to run this command on the Application ID:
New-AzureRMRoleAssignment -RoleDefinitionName Contributor -ServicePrincipalName $ApplicationId | Write-Verbose -ErrorAction SilentlyContinue

Related

Unable to run my ps script through automation account

I have a powershell script which I want to run through azure automation account. The script worked fine when running on cloudshell but when running it through a powershell runbook it is not doing the intended tasks and throwing errors.When I am using Select-AzSubscription -SubscriptionName 'xxx' it tells me to use Connect-AzAccount and when I use that it gives me Cannot find an open port error.
Can anyone help with this? I am listing down the four different error messages I am getting.
Connect-AzAccount : Cannot find an open port. At line:6 char:1 + Connect-AzAccount + ~~~~~~~~~~~~~~~~~ + CategoryInfo : CloseError: (:) [Connect-AzAccount], Exception + FullyQualifiedErrorId : Microsoft.Azure.Commands.Profile.ConnectAzureRmAccountCommand
Get-AzVM : Argument passed in is not serializable. Parameter name: value At line:19 char:12 + $vmOSDisk=(Get-AzVM -ResourceGroupName $resourceGroupName -Name $vmNa ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : CloseError: (:) [Get-AzVM], ArgumentException + FullyQualifiedErrorId : Microsoft.Azure.Commands.Compute.GetAzureVMCommand
New-AzStorageContext : Context cannot be null. Please log in using Connect-AzAccount. At line:50 char:23 + ... onContext = New-AzStorageContext -StorageAccountName $destinationstor ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : CloseError: (:) [New-AzStorageContext], InvalidOperationException + FullyQualifiedErrorId : Microsoft.WindowsAzure.Commands.Storage.Common.Cmdlet.NewAzureStorageContext
Start-AzStorageBlobCopy : Cannot bind argument to parameter 'AbsoluteUri' because it is null. At line:55 char:38 + Start-AzStorageBlobCopy -AbsoluteUri $sas.AccessSAS -DestContainer $d ... + ~~~~~~~~~~~~~~ + CategoryInfo : InvalidData: (:) [Start-AzStorageBlobCopy], ParameterBindingValidationException + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.WindowsAzure.Commands.Storage.Blo [![enter image description here][1]][1]b.Cmdlet.StartAzureStorageBlobCopy
Here is a snip of a part of code for reference. Az module is used in the script and new Azure automation account does not have Az module installed by default, even after importing Az.Accounts, Az.Automation, Az.Compute I am getting these errors.
In cloud shell, it will login your user account automatically, actually Connect-AzAccount does not work, but it will not give you an error, just a warning, so the script will work.
In the automation runbook, it does not support the interactive way to login your user account, if you use Connect-AzAccount directly, you will get the error, the other errors are follow-up issues based on this.
So to solve the issues, we always use the Run As Account of your automation account in this scenario, essentially it is an AD App along with a service principal in your AAD tenant. Make sure you have enabled it and give all the permissions to it the same as your user account to run the script, its name is like automationname_xxxxxxxxx, you can check it in the Run As Account blade in the automation account in the portal.
Then use the commands below to login.
$connectionName = "AzureRunAsConnection"
try
{
# Get the connection "AzureRunAsConnection "
$servicePrincipalConnection=Get-AutomationConnection -Name $connectionName
Connect-AzAccount `
-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
}
}
After login, please use Set-AzContext -Subscription <subscription-id> instead of Select-AzSubscription, also please import Az.Storage module in the automation account, because some commands like New-AzStorageContext and Start-AzStorageBlobCopy belong to this module, after doing them, your script should work.
Update:
I test with the script you used with Storage Blob Data Contributor, it works fine.
$connectionName = "AzureRunAsConnection"
try
{
# Get the connection "AzureRunAsConnection "
$servicePrincipalConnection=Get-AutomationConnection -Name $connectionName
Connect-AzAccount `
-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
}
}
$sas = Grant-AzSnapshotAccess -SnapshotName "joyvmsnap" -ResourceGroupName "xxxxx" -DurationInSecond 3600 -Access Read
$destinationContext = New-AzStorageContext -StorageAccountName "joystoragev2" -UseConnectedAccount
$storageContainerName="image"
$destinationVHDFileName="test.vhd"
Start-AzStorageBlobCopy -AbsoluteUri $sas.AccessSAS -DestContainer $storageContainerName -DestContext $destinationContext -DestBlob $destinationVHDFileName -Force
Make sure the firewall of the storage account is set to allow access from all networks and the Storage Blob Data Contributor role is assigned at the storage account level or higher, not the container level.

A parameter cannot be found that matches parameter name 'PasswordPolicies' in Powershell

I was trying to set the password for an Azure user to not expire forever. In the process I tried below commands
Get-AzADUser -ObjectId <valid Azure user> | Select-Object UserprincipalName,#{
>> N="PasswordNeverExpires";E={$_.PasswordPolicies -contains "DisablePasswordExpiration"}
>> }
UserPrincipalName PasswordNeverExpires
----------------- --------------------
<valid Azure user> False
To set PasswordNeverExpires to True, I executed below command
Set-AzADUser -ObjectId <valid Azure user> -PasswordPolicies DisablePasswordExpiration
But it throws an error as below:
Update-AzADUser : A parameter cannot be found that matches parameter name 'PasswordPolicies'.
At line:1 char:51
+ ... ADUser -ObjectId <valid Azure user> -PasswordPolicies Disable ...
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Update-AzADUser], ParameterBindingException
+ FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.Azure.Commands.ActiveDirectory.UpdateAzureADUserCommand
Can someone help me on this issue please.
Thanks,
Sri Ram.
Az Powershell doesn't provide the setting password policy feature.
Use Azure AD Powershell instead.
Set-AzureADUser -ObjectId <user ID> -PasswordPolicies DisablePasswordExpiration
If you are concerned about having to log in to Azure AD Powershell again, you can connect a session using an existing token associated with the active azure context.
For example:
# login
Connect-AzAccount -Tenant {your tenant}
# perform other Azure operations...
$currentAzureContext = Get-AzContext
$tenantId = $currentAzureContext.Tenant.Id
$accountId = $currentAzureContext.Account.Id
Connect-AzureAD -TenantId $tenantId -AccountId $accountId
Then you can run Set-AzureADUser cmd.

error - WARNING: The version '1.9.4' of module 'Az.Accounts' is currently in use. Powershell script run on VM in Azure cloud

Here is my powershell command sequence.
PS C:\Application01>Install-Module -Name Az -AllowClobber -Scope AllUsers
PS C:\Application01>Connect-AzAccount ### this prompts me for my azure logon
PS C:\Application01>Update-Module -Name Az
PS C:\Application01>.\Publish-Application01.ps1 -action "Deploy" `
-azureAccountApplicationId "a3XXXXXXXXXXXXXXXXXXXXXXXX76" `
-azureAccountPassword "43XXXXXXXXXXXXXXXXXXXXXXXXXXXm" `
-package "C:\Application01\Application01.server.Web.zip" `
-azureSubscriptionId "c27XXXXXXXXXXXXXXXXXXXXXXXXX32" `
-azureAccountTenantId "41XXXXXXXXXXXXXXXXXXXXXXXXX1d" `
-hostAdminPassword "XXXXXXXXXXXX" `
-defaultTenantAdminPassword "XXXXXXXXXXX" `
-resourceGroupName "RG01" `
-appServiceName "Applicationservice01" `
-nugetRepositoryType "Composite" `
-storageType "Azure" `
-storageLocation "DefaultEndpointsProtocol=https://XXXXXXXXX" `
-appSettings #{"Telemetry.Enabled"="false"} `
-verbose
WARNING: The version '1.9.4' of module 'Az.Accounts' is currently in use. Retry the operation after closing the applications.
WARNING: The provided service principal secret will be included in the 'AzureRmContext.json' file found in the user profile ( C:\Users\zzadmin\.Azure ). Please ensure that this directory has appropriate protections.
Connect-AzAccount : The provided account a3XXXXXXXXXXXXXXXXXXXX76 does not have access to subscription ID "c2XXXXXXXXXXXXXXXXXXXXXXXX2". Please try logging in with different credentials or a different subscription ID.
At C:\Application01\Publish-Application01.ps1:577 char:9
+ if (Connect-AzAccount -Environment AzureUSGovernment -ServicePrin ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [Connect-AzAccount], PSInvalidOperationException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.Profile.ConnectAzureRmAccountCommand
XXXXXXXXXXXXXXXXXX
Line 577 >>> -ServicePrincipal --
my understanding is a prompt will appear to enter a value for ServicePrincipal.
Here is the azure Function.
function AuthenticateToAzure {
$securePassword = $azureAccountPassword | ConvertTo-SecureString -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($azureAccountApplicationId, $securePassword)
if (Connect-AzAccount -Environment AzureUSGovernment -ServicePrincipal -SubscriptionId $azureSubscriptionId -TenantId $azureAccountTenantId -Credential $credential){
Write-Host "Logged in to Az" -ForegroundColor Green
} else {
Write-Error "Failed to log in to Az"
Exit 1
}
XXXXXXXXXXXXXX
I have tried rebooting the VM and error still appears.
The zzadmin account on the VM is a local administrator.
User account logon Azure is the owner role.

Set-AzVMCustomScriptExtension in catch?

Attempting to add an extension when not detected but keep failing to find the secret sauce to get this to work. Mind you I am a BASH guy and this is a first foray into PowerShell..
#requires -version 2
# Required parameter $subscription: name of the subscription to enable Custom Script Extensions in
param (
# NOTE: See below for reason...
# [Parameter(Mandatory = $true)] [String] $subscription
# NOTE: Prompting is great for using the script interactively, but if this will also be executed
# from a build server or ...
# NOTE: Once the parameter is marked as mandatory PowerShell it will prompt for value. That said,
# if you remove the mandatory attribute then you can set a default value as a T_THROW ...
# NOTE: This _does_ contain shortcomings if this will be used as a pipeline param ...
# https://stackoverflow.com/questions/33600279/is-it-possible-to-force-powershell-script-to-throw-if-a-required-pipeline-para
[Parameter()]
[ValidateNotNullOrEmpty()]
[String]$SubscriptionName=$(Throw "`SubscriptionName` is mandatory, please provide a value...")
)
# Connect to the current Azure account
Write-Output "Pulling Azure account credentials..."
Start-Process "https://microsoft.com/devicelogin" # steals focus...
# Login to Azure account
Connect-AzAccount
# Set the active subscription
$null = Get-AzSubscription -SubscriptionName "$SubscriptionName" |Set-AzContext
# TODO: error handling
$vms = Get-AzVM
$cseName = "VulnerabilityManagementTools"
ForEach ($vm in $vms) {
try {
$cseStatus = Get-AzVMCustomScriptExtension `
-ResourceGroupName $vm.ResourceGroupName `
-VMName $vm.Name `
-Name $cseName `
-Status
}
catch {
Write-Output "Enabling Custom Script Extension for $vm."
Set-AzVMCustomScriptExtension `
-ResourceGroupName $vm.ResourceGroup `
-Location $vm.Location `
-VMName $vm.Name `
-Name $cseName `
-TypeHandlerVersion "1.1" `
-StorageAccountName "VulnerabilityManagementTools" `
-FileName "VulnerabilityManagementInstaller.ps1" `
-ContainerName "VulnerabilityManagementTools"
}
}
End up err'ing out with
PS /.../automation-scripts> ./EnableCustomScriptExtension.ps1 SubscriptionName
Pulling Azure account credentials...
WARNING: To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code XXXXXX to authenticate.
Account SubscriptionName TenantId Environment
------- ---------------- -------- -----------
XXXX#analytics.com SubName XXXXXX-XXXX AzureCloud
Get-AzVMCustomScriptExtension : The Resource 'Microsoft.Compute/virtualMachines/XXXX/extensions/VulnerabilityManagementTools' under resource group '{NAME}' was not found.
ErrorCode: ResourceNotFound
ErrorMessage: The Resource 'Microsoft.Compute/virtualMachines/XXXX/extensions/VulnerabilityManagementTools' under resource group '{NAME}' was not found.
ErrorTarget:
StatusCode: 404
ReasonPhrase: Not Found
At /.../automation-scripts/EnableCustomScriptExtension.ps1:59 char:18
+ $cseStatus = Get-AzVMCustomScriptExtension `
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [Get-AzVMCustomScriptExtension], ComputeCloudException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.Compute.GetAzureVMCustomScriptExtensionCommand
Get-AzVMCustomScriptExtension : The Resource 'Microsoft.Compute/virtualMachines/XXXXX/extensions/VulnerabilityManagementTools' under resource group '{RESOURCE_GROUPNAME}' was not found.
ErrorCode: ResourceNotFound
ErrorMessage: The Resource 'Microsoft.Compute/virtualMachines/XXXX/extensions/VulnerabilityManagementTools' under resource group '{RESOURCE_GROUPNAME}' was not found.
ErrorTarget:
StatusCode: 404
ReasonPhrase: Not Found
At /.../automation-scripts/EnableCustomScriptExtension.ps1:59 char:18
+ $cseStatus = Get-AzVMCustomScriptExtension `
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [Get-AzVMCustomScriptExtension], ComputeCloudException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.Compute.GetAzureVMCustomScriptExtensionCommand
Get-AzVMCustomScriptExtension : The Resource 'Microsoft.Compute/virtualMachines/{VMName}/extensions/VulnerabilityManagementTools' under resource group '{RESOURCEX_GROUPNAME}' was not found.
ErrorCode: ResourceNotFound
ErrorMessage: The Resource 'Microsoft.Compute/virtualMachines/{VMName}/extensions/VulnerabilityManagementTools' under resource group '{RESOURCEX_GROUPNAME}' was not found.
ErrorTarget:
StatusCode: 404
ReasonPhrase: Not Found
At /.../automation-scripts/EnableCustomScriptExtension.ps1:59 char:18
+ $cseStatus = Get-AzVMCustomScriptExtension `
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [Get-AzVMCustomScriptExtension], ComputeCloudException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.Compute.GetAzureVMCustomScriptExtensionCommand`
In your case, you just need to use the if(){}else{} statement, try the script as below instead of the ForEach part of yours, it works fine on my side.
ForEach ($vm in $vms) {
$cseStatus = Get-AzVMCustomScriptExtension `
-ResourceGroupName $vm.ResourceGroupName `
-VMName $vm.Name `
-Name $cseName `
-Status `
-ErrorAction SilentlyContinue
if ($cseStatus){
Write-Host "The extension has been set for" $vm.Name
}else{
Write-Host "Enabling Custom Script Extension for" $vm.Name
Set-AzVMCustomScriptExtension `
-ResourceGroupName $vm.ResourceGroup `
-Location $vm.Location `
-VMName $vm.Name `
-Name $cseName `
-TypeHandlerVersion "1.1" `
-StorageAccountName "VulnerabilityManagementTools" `
-FileName "VulnerabilityManagementInstaller.ps1" `
-ContainerName "VulnerabilityManagementTools"
}
}
Test result:
You'll need to create an Azure AD Service Principal using password authentication and use the credentials of this to pass to the Connect-AzAccount cmdlet as follows:
$credentials = Get-Credential
Connect-AzAccount -ServicePrincipal -Credentials $credentials
The service account will need to have the necessary permissions to use the Set-AzVMCustomScriptExtensions cmdlet.
More information on creating the service account here:
https://learn.microsoft.com/en-us/powershell/azure/create-azure-service-principal-azureps?view=azps-2.8.0

Authenticated with "Login-AzureRmAccount -ServicePrincipal" but no subscription is set?

I've successfully created a self-signed certificate with application & service principle using the New-AzureRmADApplication and New-AzureRmADServicePrincipal cmdlets.
I can execute the login using this command after retrieving the certificate:
Login-AzureRmAccount -ServicePrincipal -CertificateThumbprint $cert.Thumbprint -TenantId $tenantID -ApplicationId $applicationID
However, the SubscriptionId/SubscriptionName attributes of this authentication display as blank:
Environment : AzureCloud
Account : ********************
TenantId : ********************
SubscriptionId :
SubscriptionName :
CurrentStorageAccount :
Subsquently, this command works!
$secret = Get-AzureKeyVaultSecret -VaultName $vaultName -Name $keyName
What is confusing to me is that I am able to retrieve a AzureKeyVaultSecret in my DEV subscription, but I do not understand how this cmdlet knows which of my subscriptions to use??? I intend to create the same vault in my PROD subscription, but first need to understand how this ServicePrincipal/Certificate authentication knows which subscription to pull from and/or how to manipulate it?
I can say that when I created the App/ServicePrincipal, I logged in specifying the "DEV" subscription like so:
$subscriptionName = "DEV"
$user = "user#company.com"
$password = "*****"
$securePassword = ConvertTo-SecureString $password -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential ($user, $securePassword)
Login-AzureRmAccount -Credential $credential -SubscriptionName $subscriptionName

Resources