Update : updated script to support Azure Az powershell module.
Azure AD Application is an identity with some configurations on cloud. When you register an Azure AD application in Azure portal , two objects are created in your Azure AD Tenant :
- An application object
- A service principal object
Application object
An Azure AD application is identified by its one and only application object,which resides in the Azure AD tenant where the application was registered, knows as the application’s “home” tenant (from Microsoft documentation).
Service principal object
To access resources that are secured by an Azure AD tenant, the entity that requires access must be represented by a security principal. This is true for both users (user principal) and applications( service principal). The security principal defines the access policy and permissions for the user/application in the Azure AD tenant. This enables core features such as authentication of the user/application during sign-in, and authorization during resource access (from Microsoft documentation).
Refer Microsoft documentation for more details about Azure AD applications.
Every service principal object has a Client Id , also referred as application Id. We do set an application secret also knows as Client secret to use the service principal object to authorize access to Azure resources.
Every client secret we set has an expiration, even if it is set to “Never”. As a best security practice, we usually set it to the lowest time period.
It is always great to know prior to the application secret expires , so that , we can proactively create a new secret and update it in places to stop unwanted application downtime.
Today I am going to share a script which helps me to generate a list of all Azure AD application with details , including client secret expiration date. This can be further processed to create email notifications to application owner or support team for necessary action or can be automated to generate a new secret and update Azure Key Vault. I might share another script on how to set it up soon.
So, let’s start scripting. As we will be dealing with Azure Active Directory, we need an user account with “Application Administrator” or “Global Reader” role assigned to the user id. You need to set this up through Azure Active Directory.
I am storing the user name and password to be used to connect to Azure AD in a Key Vault and will retrieve it in the script.
Make sure you have Azure Az Module installed and imported on the system before running this script. For more information on how to install and configure Az module refer following article : https://docs.microsoft.com/en-us/powershell/azure/new-azureps-module-az?view=azps-5.5.0
We also need to import Powershell module for Azure AD, which we will do in the script it self. To run the script , login to your azure account using Login-AzAccount. If you are planning to run it as an automation run book, add the following script block to your script. In that case also, you need to import Powershell Az module in the automation account.:
#region - login to Azure from the Automation Account
$connectionName = "AzureRunAsConnection"
try{
$servicePrincipalConnection = Get-AutomationConnection -Name $connectionName
"Logging in to Azure..."
Add-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
}
}
#endregion
Now, defining the output file name and initial header how for the csv file. I am storing it in my current working directory. You may change it based on where do you want to store it.
#region - define output file to store the .csv output
$date = Get-Date -UFormat "%m-%d-%Y"
$currentDir = $(Get-Location).Path
$oFile = "$($currentDir)\AzureAD_Application_Details_$($date).csv"
if(Test-Path $oFile){Remove-Item $oFile -Force}
"Application Name, Object Type, Object Id,Application Id,Is Multitenant,Home Page,Identifier URLs,Reply URLs,Password Key Id, Password Expiration" | Out-File $oFile -Append -encoding ASCII
#endregion
After that, define the key vault name which has the user id and password stored as secrets.
#region - declare key vault name
$kvName = <key vault name>
#endregion
Next, retrieve user account credentials from key vault as shown below. I am using “AzureADSvcAccount” as key vault secret name for user name and “AzureADSvcAccountPassword” as password. After that, I am converting the password as encrypted string and storing credentials in to an object.
#region - Retrieve Azure AD Service Account Credentials from Key Vault
$azADSvcAcc = (Get-AzureKeyVaultSecret -VaultName $kvName -Name AzureADSvcAccount).SecretValueText
$azADSvcAccPwd = (Get-AzureKeyVaultSecret -VaultName $kvName -Name AzureADSvcAccountPassword).SecretValueText
$password = ConvertTo-SecureString $azADSvcAccPwd -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential ($azADSvcAcc, $password)
#endregion
Now, as mentioned earlier, I am checking if AzureAD powershell module is already imported, if not will import it here and then connect to Azure AD using the credential created in previous state.
#region - import AzureAD Module if it is not already imported and then connect to Azure AD
if((Get-Module -Name AzureAD).count -gt 0){
Write-Output "Azure AD Module is already imported"
}else{
Write-Output "Azure AD Module is missing. Importing Module."
Import-Module AzureAD -Force
}
Connect-AzureAD -Credential $Cred
#end - region
Finally, it is parsing through all Azure AD Applications using Get-AzureADApplication and storing it in a csv file containing all different fields. I have included fewer properties for my requirements. However, you can add whatever data you need from the list of available properties.
#region - Check Azure AD and generate report on each Azure AD Application
Get-AzureADApplication -All $true | ForEach-Object{
$applicationName = $objectType = $objectId = $applicationId = $multiTenant = $homePage = $identifierUrls = $replyUrls = $keyId = $passwordExpiration = ""
$applicationName = $_.DisplayName
$objectType = $_.ObjectType
$objectId = $_.ObjectId
$applicationId = $_.AppId
$multiTenant = $_.AvailableToOtherTenants
$homePage = $_.Homepage
$identifierUrls = $_.IdentifierUris -Join ","
$replyUrls = $_.ReplyUrls -Join ","
(Get-AzureADApplication -ObjectId $objectId).PasswordCredentials | ForEach-Object{
$keyId = $_.KeyId
$passwordExpiration = $_.EndDate
"$applicationName,$objectType,$objectId,$applicationId,$multiTenant,$homePage,$identifierUrls,$replyUrls,$keyId,$passwordExpiration" | Out-File $oFile -Append -encoding ASCII
}
}
#endregion
That’s it! Now you should have details of Azure AD Applications. If you want to further automate with either email alert or updating key vault with a new secret, you can add those sections as discussed earlier. I will try to update it with those options in a later blog.
Let me know if you have any issue running this script.
[…] my previous blog, I provided a script to generate an inventory of all Azure AD Application registered along […]