Unable to connect-AZAccount in Azure Automation with a Service Principal - azure

I have an Azure Automation Runbook that needs to Connect-AzAccount to export a CSV from the Automation Account to a Blob Storage Account. My Service Principal has an ApplicationID and a Secret. per the documentation for Connect-AzAccount -Credential can accept this.
However when I attempt to feed it in via:
$Credential = New-Object -TypeName System.Management.Automation.PSCredential($ApplicationID, $AppSecret)
Connect-AzAccount -ServicePrincipal -TenantId $TenantId -Credential $Credential
I get the following error:
Cannot bind argument to parameter 'Credential' because it is null
Would anyone be able to point me to where I am messing up?

tl;dr
Since the root cause turned out to be the following error:
Cannot find overload for "PSCredential" and the argument count: "2".
the implication is that the $AppSecret argument in your New-Object -TypeName PSCredential call was not of type [securestring], which is what the relevant [pscredential] constructor overload requires.
Making it a [securestring] instance solved your problem.
A [securestring] instance can be constructed or obtained in several ways:
Preferably, load the secret from a secrets-management system, such as the Microsoft.PowerShell.SecretManagement module, which supports various extension modules implementing vaults (secrets stores), such as Microsoft.PowerShell.SecretStore for local file-system storage and the Az.KeyVault module for retrieving secrets from an Azure Key Vault.
[Not advisable for security reasons] Use ConvertTo-SecureString -AsPlainText to convert a plain-text representation of the secret to a [securestring].
Alternatively, you could obtain the entire [pscredential] instance differently:
Interactively, via Get-Credential:
# Prompts for the app secret (password) and returns a [pscredential] instance.
$Credential = Get-Credential $ApplicationID
On Windows only, import a [pscredential] instance that was previously persisted to a file with Export-Clixml with Import-Clixml - see this answer.
A general caveat: [securestring] offers limited security on Windows, and virtually none on Unix-like platforms, where encryption isn't even employed - see this answer.
As for what you tried and the error message you saw:
New-Object -TypeName System.Management.Automation.PSCredential($ApplicationID, $AppSecret)
This command can be simplified to:
New-Object pscredential $ApplicationID, $AppSecret
# Short for:
# New-Object -TypeName pscredential -ArgumentList $ApplicationID, $AppSecret
Note:
The use of short name pscredential, given that it is a type accelerator for the full type name, System.Management.Automation.PSCredential.
The absence of (...) around the arguments, as that amounts to pseudo method syntax that is best avoided - see this answer.
New-Object calls translate into .NET constructor calls, and in PowerShell 5 and above there's now a a more direct way to call constructors, using the static ::new() method exposed by PowerShell on types. Therefore, the equivalent of the command above is:
# PSv5+ equivalent of the above.
# Note that this syntax *does* require method-call syntax.
[pscredential]::new($ApplicationID, $AppSecret)
The advantage of this approach is that you can easily inspect the constructor overloads (variants with different parameters), simply by accessing ::new without the (...) part:
# Print constructor overloads
[pscredential]::new
Output:
OverloadDefinitions
-------------------
pscredential new(string userName, securestring password)
pscredential new(psobject pso)
The first overload - the only one to accept two arguments - also reveals the parameter types, and indeed shows that the second parameter requires a [securestring] instance as its argument.
Unfortunately, the error message you get when the count of arguments is correct but the type isn't is somewhat misleading:
Cannot find overload for "PSCredential" and the argument count: "2".
Clearly, you did pass 2 arguments, but it was the fact that the 2nd argument had the wrong type that triggered the error, whereas the message makes it sound like you passed the wrong number of arguments.
Improving this error message has been green-lit in GitHub issue #3658, but so far no one has stepped up to implement it.

Related

Why does Get-AzKeyVaultSecret return "No Such Host Is Known"?

I am trying to run a PowerShell script that calls Get-AzKeyVaultSecret using examples provided per Microsoft and keep getting an error stating No such host is known.
Generically, the error is simple enough but the fact that I'm not specifying a host address or IP during the call makes the error seem very abstract from the actual issue.
Line |
14 | Get-AzKeyVaultSecret -VaultName $KeyVaultName -Name $SecretName
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| No such host is known.
I have tried just about everything I can think of to get this working and this is the error I receive everytime. I've checked that I have the appropriate privileges in Azure Access Policies and also check that I have the Access Control roles and etc. So I don't understand the error message.
I was previously attempting this using the AzureRM Powershell module but since realizing it is soon due for deprecation within a couple of years; I opted to go this route but it doesn't seem to be working.
What exactly does no such host mean and how do I resolve the problem? I am running under PowerShell 7
Because of the 1st comment regarding posting the remainder of the Script; I'll add that I receive the same error when calling the method directly in the PowerShell window.
PS C:\SQL Scripts\PowerShell> Get-AzKeyVaultSecret -VaultName 'myKeyVaultName' -Name 'myKeyVaultSecretName'
Get-AzKeyVaultSecret: No such host is known.
SHORT VERSION ANSWER:
The environment needs to be specified when working within private sectors such as Government, Education and etc.
LONG ANSWER/EXPLANATION:
The comment by #Ked Mardemootoo led me to view the issue from a different perspective. In a manner of sorts, the issue was determined to be somewhat network related and perhaps arguably a "DNS" issue but not a DNS issue as it were to relate to the system from where the call is being made.
The Get-AzKeyVaultSecret module performs some work underneath the hood which includes resolving the FQDN of the requested resource among other things using the Credentials provided to connect via the Connect-AzAccount module
In most common scenarios these requests are routed to Azure on the public networks but on a comparatively smaller scale where Azure is on a private sector/network e.g. Educational, Government and etc. there is an additional parameter switch where the Environment needs to be specified.
Connect-AzAccount
Connects User within public domain
Connect-AzAccount -Environment
Connects User within the private domain/sector specified with the Environment switch
If you have an Azure account, both methods will log you onto the Azure platform but if you're on a private sector and attempt to subsequently use modules to acquire information or resources without having designated the environment; you will receive the no such host is known
The error is somewhat cryptic and abstract and in my opinion should have been more specific to better clue the user as to the actual problem. Such as Resource not found or something similar.
Once I specified the Environment (something that isn't front and center in the documentation that I accessed); the module functioned as expected.
Hopefully this information helps others from falling into this pit of obscurity.
It appears there's something wrong with the DNS resolution on your machine.
I'd suggest running the command from a different device or from the Azure CloudShell to narrow it down further.
I've tried to replicate it on my end (within my context/subscription) to see what kind of error message shows up in different scenarios.
Wrong KV name shows clear error message:
PS /Users/kedmardemootoo> Get-AzKeyVaultSecret -VaultName 'kv-wrong-name' -Name 'correct-secret-name'
Get-AzKeyVaultSecret: nodename nor servname provided, or not known
Correct KV name but wrong Secret doesn't show any error/output:
PS /Users/kedmardemootoo> Get-AzKeyVaultSecret -VaultName 'kv-correct-name' -Name 'wrong-secret-name'
Correct KV and secret name but no access via access policies:
PS /Users/kedmardemootoo> Get-AzKeyVaultSecret -VaultName 'kv-correct-name' -Name 'wrong-secret-name'
Get-AzKeyVaultSecret: Operation returned an invalid status code 'Forbidden'
Correct KV and secret name with the right access policies:
PS /Users/kedmardemootoo> Get-AzKeyVaultSecret -VaultName 'kv-correct-name' -Name 'correct-secret-name'
Vault Name : kv-correct-name
Name : correct-secret-name
Version : 0abbb10de45a1235f5544
Id : https://kv-correct-name.vault.azure.net:443/secrets/correct-secret-name/0abbb10de45a1235f5544
Enabled : True
Expires : 06/03/2022 05:20:05
Not Before :
Created : 06/03/2022 05:29:07
Updated : 06/03/2022 05:34:09
Content Type :
Tags :
Get-AzKeyVaultSecret -VaultName 'myKeyVaultName' -Name 'myKeyVaultSecretName' -Debug
You can toggle -Debug switch to see the "Absolute Uri". You will see something like:
https://myKeyVaultName.vault.azure.net/secrets/myKeyVaultSecretName
You will get an error (no such host is known) if there is a typo in the VaultName or the VaultName does not exist.

Azure Devops: value cannot be null, parameter token

I am running an Azure Powershell task in Azure DevOps.
Inside the script I use the following command
Get-AzureRmADUser -UserPrincipalName $adusernameNewPermission
But my Release pipeline fails with following error code
##[error]Value cannot be null.
Parameter name: token
First I thought that the command didn't have the right context or enough permission so I've added the defaultprofile.
Get-AzureRmADUser -DefaultProfile (Get-AzureRmContext) -UserPrincipalName $adusernameNewPermission
The GetAzureRmContext did go to the right context if I print the output of that command.
The command itself didn't had any problem when running locally (with my own user account) So the only reason I think its heading is that the service connection doesn't have the right to perform that action. But my user account has the least permissions on the tenant whilst the service connnection in azure devops has much more permissions.
It's driving me crazy where the problem lays with this one. Which token does it mean ? No reasonable error message :(
Does someone encounter the same problem or knows what I am missing ?
PS: the $adusernameNewPermission variable works like I said the exact same code runs perfectly on my local machine with the only difference being the user that is logged in.
Did you try using Get-azureaduser instead? This is a command that requires the function to be authenticated against Azure AD.
$azurePassword = ConvertTo-SecureString $env:client_secret -AsPlainText -Force
$psCred = New-Object System.Management.Automation.PSCredential($env:clientid , $azurePassword)
Connect-AzAccount -Credential $psCred -TenantId $env:tenantid -ServicePrincipal
If you're using the Script Type of "Script File Path," check that you're not trying to pass in any arguments (such as -token).
I'd try 2 things to get back to basics. This will let you know if it is actually the AzDO Service Principal or not and the type of object to use in the pipeline.
Test the functionality of the command in its simplest form and run it with the account as a string:
Get-AzureRmADUser -UserPrincipalName "achahbar#stankoverflow.com"
#OR
$UPN = "achahbar#stankoverflow.com"
Get-AzureRmADUser -UserPrincipalName $UPN
Assuming this works and depending on what your variable contains you simply need to pass the the UPN/Email object into the command:
Get-AzureRmADUser -UserPrincipalName $adusernameNewPermission.UPN
If this doesn't work pdate your task to Version 4 (Preview) and update your commands to Get-AzADUser and test step 1. again
I fixed this issue by changing the service connection in Azure DevOps that was created with a managed identity. I created a new service connection with a service principal and this doesn't gave me any errors about the value token. Hope any person who looks for this issue in the future got an answer by this.

Applying PnP Provisioning template with Azure Functions/Powershell

I'm currently trying to develop a Flow which creates a SharePoint site and then utilizes an Azure Function to provision said site with a selection of libraries and such.
The Flow itself is pretty straight forward, but the bit I'm struggling with is the Azure Function itself, particularly the authentication; It uses a Connect-PnPOnline cmdlet, and with our tenant using MFA I've had a bit of difficulty getting around it - I've created a Service Principal User which at the very least has enabled me to connect to the site, but I still can't actually use Apply-PnPProvisioningTemplate, nor any other PnP commands really - when I try and do so, I get:
"The remote server returned an error: (403) Forbidden."
My Service Principal user has Contribute permissions, and a scope of Sites.FullControl.All, so I'm not sure where I'm going wrong.
See below the Powershell code - I don't think the issue is really arising from there but it can't hurt to show:
$requestBody = Get-Content $req -Raw | ConvertFrom-Json
"destination": "SharePointSiteURL"
$destination = $requestBody.destination
$secpasswd = ConvertTo-SecureString $env:pass -AsPlainText -Force
$mycreds = New-Object System.Management.Automation.PSCredential ($env:user, $secpasswd)
Connect-PnPOnline -url $destination -AppID $env:user -AppSecret $env:pass
Apply-PnPProvisioningTemplate -path "D:\home\site\wwwroot\template.xml"
Out-File -Encoding Ascii -FilePath $res -inputObject "Done $destination"
I should note that this is actually my first time using Azure Functions so forgive me if the solution here is quite simple! Any help would be appreciated.
Referring to MSDN Thread
https://social.msdn.microsoft.com/Forums/en-US/53629265-47da-41f7-b780-35eaba999f73/applying-pnp-provisioning-template-with-azure-functionspowershell?forum=AzureFunctions
This post work https://www.sharepointfire.com/2018/04/sharepoint-online-pnp-site-provisioning-using-flow-and-azure-function/

How do you access environment variables in an Azure function app written in powershell?

I am writing an Azure function app in powershell (runtime 2.0.12507.0).
To perform an operation in my function app, it must authenticate with Azure using the Connect-AzAccount function. I store the sensitive credentials used to connect in 'Manage > Function keys', but I cannot access these keys programmatically.
I have already tried using $Env:NAME_OF_MY_KEY to access the key value, but the value is coming up as null or empty when I try this. From what I understand, 'Function keys' are simply environment variables, and should be accessible this way.
using namespace System.Net
# Input bindings are passed in via param block.
param($Request, $TriggerMetadata)
# Get the service principal secret as a secure string
$secpasswd = ConvertTo-SecureString $env:SP_Secret -AsPlainText -Force
# Create a new PSCredential using the principal secret and app id
$mycreds = New-Object System.Management.Automation.PSCredential ($env:SP_AppID, $secpasswd)
# Connect to the Azure account using the powershell credentials and tenant id
$result = Connect-AzAccount -ServicePrincipal -Tenant $env:SP_Tenant -Credential $mycreds
I am expecting to be able to access these function keys; however, even if I echo out the value of $env:SP_Secret, I still get an empty string. Is this the correct way to access function keys in an Azure Function App?
Function keys are not exposed as environment variables. To set environment variables, you must set them in application settings.
Here, you can see the 'Manage application settings' link when you navigate to your function app.
Then, you may add a key here.
With the help of Key Management API you can GET PUT POST keys using http requests. You don't have to re-add the keys as environment variables.
You can find the KEY MANAGEMENT API Docs here on Github

Running New-AzureRmResourceGroupDeployment from within a Function App

I need to wire up a stateless worker ad-hoc to perform a long running job based off a user action that self destructs when its done. I am trying to run New-AzureRmResourceGroupDeployment from within a PoSh Function App and cannot figure out how to authenticate to Azure from within the PoSh script.
I tried this:
$accountName = "myID#mydomain.com"
$pwd = ConvertTo-SecureString "password" -AsPlainText -Force
$cred = new-object PSCredential($accountName, $pwd)
Add-AzureRmAccount -Credential $cred
New-AzureResourceGroupDeployment -ResourceGroupName yadda yadda
And I get an error message that I need to use an Organization ID (which I am, our Azure AD is federated and we use AD Sync (and SiteMinder w/o WS-* if that matters)):
Add-AzureRmAccount : -Credential parameter can only be used with Organization ID credentials. For more information, please refer to http://go.microsoft.com/fwlink/?linkid=331007&clcid=0x409 for more information about the difference between an organizational account and a Microsoft account.
I tried "Login-AzureRMAccount -Credential $cred" with similar results.
If I do the Add- or Login- cmdlets from a PoSh window on my local machine (which is member joined to AD) with the -Credential flag I get a similar error. If I run the cmdlets without the credential I am prompted for credentials through an interactive ID/PW window (I do not have to enter my password once I type in my ID).
Does anyone know how I can do the authentication? I would be okay with authenticating like above, some sort of pass through credential from our web layer, or even an Option C I don't know about.
You will need to use service principal for authentication. A sample with instructions can be found here.
Azure Function role like permissions to Stop Azure Virtual Machines
For that you would need to use Service Principal auth. I don't think there is any sense of copypasting Azure Doc's to this answer, just consult this document:
https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-authenticate-service-principal

Resources