How to retrieve Azure Service Principal's secret in Powershell 7 - azure

I recently started using PowerShell 7.x and I've came around some problems. I am not able to retrieve the secret of my service principal when I create it through PowerShell 7. The return body does not give the "Secret" property. I used to work with PowerShell 5.x and I used to get a "Secret" property in the return object after creating a service principal. I've added the screenshots of creating service principal through both PowerShell 7.x and PowerShell 5.x.
As you can see while working with Powershell 5 I could just use an object and save the returned object in it and access the secret like:
$sp = New-AzADServicePrincipal -DisplayName "xyz"
$secret = $sp.Secret
$plainSecret = convertFromSecureString $secret
convertFromSecrureString is just a basic function which converts the secret to plain text.
But I cannot use the same approach with PowerShell 7. How can I retrieve the secret?

$sp = New-AzADServicePrincipal -DisplayName "xyz" $secret = $sp.Secret
$plainSecret = convertFromSecureString $secret
We have tested the above shared cmdlets in our local environment which has PowerShell running with different versions 5.1 & 7.2.
Using those cmdlets we are able to create the service principal & able to see the same properties in the output in either of both versions.
Here is the sample output screenshot for reference :

New-AzADServicePrincipal returns the IMicrosoftGraphServicePrincipal structure, which didn't match the example code.
IMicrosoftGraphServicePrincipal Interface (latest PS version)
Here is the code that works for me:
Connect-AzAccount -Tenant 'TENANT_ID' -Subscription 'SUBSCRIPTION_ID'
$sp = New-AzADServicePrincipal -DisplayName $Name
$clientsec = [System.Net.NetworkCredential]::new("", $sp.passwordCredentials.secretText).Password
$jsonresp =
#{clientId=$sp.appId
clientSecret=$clientsec
}
$jsonresp | ConvertTo-Json

Related

how do I retrieve the password from the MicrosoftGraphPasswordCredential object

I have to update a Script which should create an application in Azure and subsequently use it to traverse resources.
Among the commands to update is to create a credential for the application created.
$AppSPN = New-AzADServicePrincipal -DisplayName "Move_Validation_SPN"
subsequently I need to use a credential to traverse the resources, according to the same Microsoft documentation, it can be created like this:
$creds = New-Object `
-TypeName "Microsoft.Azure.PowerShell.Cmdlets.Resources.MSGraph.Models.ApiV10.MicrosoftGraphPasswordCredential" `
-Property #{ 'DisplayName' = $name; 'StartDateTime' = $startDate; 'EndDateTime' = $endDate }
New-AzADAppCredential -ApplicationId $AppSPN.appId -PasswordCredentials #creds
Here comes the question, when I create a Token, how do I retrieve the password from the MicrosoftGraphPasswordCredential object? which is: $creds
$Token = Get-Token -TenantId $TenantId -SubscriptionID $SourceSub.Id -ApplicationID $AppSPN.appID -ApplicationKey $creds
From version 6.6.0, there are breaking changes in this cmdlet New-AzADAppCredential.
As mentioned in this MS Doc, Az PowerShell cmdlets module moved from Azure AD Graph to Microsoft Graph. So, it is better to use the cmdlet of New-AzureADApplicationPasswordCredential.
Workaround:
As mentioned here, there should be a mistake in the official doc, in the example, it uses the New, not Get.If you try New, it appears like the doc.
Source: New-AzureADApplicationPasswordCredential

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

Get-MsolUserRole Azure AD V2 cmdlet equivalent

I currently try to migrate an existing PowerShell script that uses the old MSOnline PowerShell module to the AzureAD (V2) module. I am able to replace most of the cmdlets but I don't find a replacement for the Get-MsolUserRole cmdlet to retrieve administrator roles for a specific user.
The similar AzureAD (V2) cmdlets doesn't allow me to query the roles by the objectId of the user (they require the role objectid).
Any suggestions?
The closest equivalent is Get-AzureADUserMembership, but since this will also include other membership (e.g. group memberships), you will need to filter the results down to only directory roles:
Get-AzureADUserMembership -ObjectId "user#example.com" -All $true `
| Where-Object { $_.ObjectType -eq "Role" }

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

How to add application to Azure AD programmatically?

I want to automate the creation of my application in Azure AD and get back the client id generated by Azure AD.
Are there PowerShell commandlets to do this? Is there some other means, like an API of doing this besides the management console?
Can you point me to an example?
Thanks!
There are a number of ways you can create an application in AAD Programatically. I will briefly cover two different ways you can go about doing this: PowerShell CMDLETs and the Graph API. In general, I would strongly reccommend using the Graph API for this.
PowerShell:
There are a few different modules running around that have the ability to create AAD Applications/Service Principals. If you need to create a new application object in your tenant, you can use Azure PowerShell to make the following call:
https://msdn.microsoft.com/en-us/library/mt603747.aspx
PS C:\> New-AzureRmADApplication -DisplayName "NewApplication" -HomePage "http://www.Contoso.com" -IdentifierUris "http://NewApplication"
If you need to create a service principal for your application in your tenant you can use Azure AD PowerShell:
https://msdn.microsoft.com/en-us/library/azure/jj151815.aspx
https://msdn.microsoft.com/en-us/library/azure/dn194119.aspx
New-MsolServicePrincipal -ServicePrincipalNames #("MyApp/Contoso.com") -DisplayName "My Application"
Graph API:
(recommended)
You can also create applications by making a POST to our Graph API:
https://msdn.microsoft.com/Library/Azure/Ad/Graph/api/entity-and-complex-type-reference#ApplicationEntity
We have samples that show how you can register and create an applicatoin to target the Graph API, and use the Graph Client Library to assist you in making the correct calls to the API:
https://github.com/AzureADSamples/WebApp-GraphAPI-DotNet
I hope this helps!
I'm a little late to the party - but I recently encountered this challenge too. Here are the relevant excerpts from my solution...
First you need to get the authentication token. For this you can use this handy function.
function GetAuthToken
{
param
(
[Parameter(Mandatory=$true)]
$TenantName
)
$adal = "${env:ProgramFiles(x86)}\Microsoft SDKs\Azure\PowerShell\ServiceManagement\Azure\Services\Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
$adalforms = "${env:ProgramFiles(x86)}\Microsoft SDKs\Azure\PowerShell\ServiceManagement\Azure\Services\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll"
[System.Reflection.Assembly]::LoadFrom($adal) | Out-Null
[System.Reflection.Assembly]::LoadFrom($adalforms) | Out-Null
$clientId = "1950a258-227b-4e31-a9cf-717495945fc2"
$redirectUri = "urn:ietf:wg:oauth:2.0:oob"
$resourceAppIdURI = "https://graph.windows.net"
$authority = "https://login.windows.net/$TenantName"
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
$authResult = $authContext.AcquireToken($resourceAppIdURI, $clientId,$redirectUri, "Auto")
return $authResult
}
(borrowed from Paulo Marques https://blogs.technet.microsoft.com/paulomarques/2016/03/21/working-with-azure-active-directory-graph-api-from-powershell/)
You can then submit a POST request to the Azure Active Directory Graph API in order to create your application. However there is a little setup required.
# The name of this AAD instance
$global:tenant = "mycompany.onmicorosft.com"
$global:aadSecretGuid = New-Guid
$global:aadDisplayName = "azure-ad-displayname"
$global:aadIdentifierUris = #("https://contoso.com")
$guidBytes = [System.Text.Encoding]::UTF8.GetBytes($global:aadSecretGuid)
$global:aadSecret = #{
'type'='Symmetric';
'usage'='Verify';
'endDate'=[DateTime]::UtcNow.AddDays(365).ToString('u').Replace(' ', 'T');
'keyId'=$global:aadSecretGuid;
'startDate'=[DateTime]::UtcNow.AddDays(-1).ToString('u').Replace(' ', 'T');
'value'=[System.Convert]::ToBase64String($guidBytes);
}
# ADAL JSON token - necessary for making requests to Graph API
$global:token = GetAuthToken -TenantName $global:tenant
# REST API header with auth token
$global:authHeader = #{
'Content-Type'='application/json';
'Authorization'=$global:token.CreateAuthorizationHeader()
}
Now you can hit the Graph API.
$resource = "applications"
$payload = #{
'displayName'=$global:aadDisplayName;
'homepage'='https://www.contoso.com';
'identifierUris'= $global:aadIdentifierUris;
'keyCredentials'=#($global:aadSecret)
}
$payload = ConvertTo-Json -InputObject $payload
$uri = "https://graph.windows.net/$($global:tenant)/$($resource)?api-version=1.6"
$result = (Invoke-RestMethod -Uri $uri -Headers $global:authHeader -Body $payload -Method POST -Verbose).value
Once the response comes back, you can extract the configuration values you need.
# Extract configuration values
$keyObject = foreach($i in $result.keyCredentials) { $i }
# Tenant ID
$global:aadTenantId = Get-AzureRmSubscription | Select-Object -ExpandProperty TenantId
# Application object ID
$global:aadApplicationObjectId = $result | Select-Object -ExpandProperty objectId
# App ID / Client ID
$global:aadClientId = $result | Select-Object -ExpandProperty appId
# Application Secret/Key
$global:aadAppSecret = $keyObject | Select-Object -ExpandProperty keyId
I hope this helps somebody!
Microsoft has released a couple of additional PowerShell cmdlets to register an app and set credentials:
New-AzureRmADApplication
New-AzureRmADServicePrincipal
New-AzureRmRoleAssignment
Add-AzureADApplicationCredential
Please review their documentation:
https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-authenticate-service-principal
I've written some powershell scripts which will
Create AAD applications (thanks mainly to Matt's answer)
Create a Key Vault in Azure
Create a key in the Key Vault
Assign permissions to the key vault for the AAD applications
I know this is more than what you're asking for, but if, like me, you're interested in getting back the secret (aka key) from the application (the same one you add in the portal which you have to copy before never seeing it again), then the second script will allow you to explicitly send that in as part of the payload in a call to the Graph API. The script will save that to a file for you to refer to later.
The other scripts are not really what you're asking about, but you may still find them useful if you ever need to set up SQL Server to work with Azure Key Vault for TDE or column-level encryption.

Resources