#
.SYNOPSIS
This script generates an report with all the App Secrets of the Azure applications
.DESCRIPTION
This PowerShell script connects to the Microsoft Graph API, retreives all the Applications that are configured in the Azure Tenant and make use of an secret
with a expiration date. Finaly the script will create a report based on the information collected by The GraphAPI.
.PARAMETER None
This script does not require any parameters.
.EXAMPLE
.\Azure-App-Expiration.ps1
.NOTES
This script is intended for use in a test or production environment. Make sure to test the script in a non-production environment before running it in production.
Author: D.de Kooker - info@dcomputers.nl
DISCLAIMER: Use scripts at your own risk, if there is anything I can help you with I will try but I do not take responsibility for the way that anyone else uses my scripts.
Sharing is caring. Share your knowledge with the world so that everybody can learn from it.
.LINK
The latest version can Always be found on my GIT page on the link below:
https://git.dcomputers.nl/Dcomputers/PowershellScripts
#>
#region Global script settings and variables
#General
$Version = "v1.1"
$logfilelocation = "$($MyInvocation.MyCommand.Path | Split-Path -Parent)\Logs"
$logfilename = "$(Get-Date -Format yyyyMMddHHmmss)-Azure-App-Expiration-Report.log"
$summaryfilename = "$(Get-Date -Format yyyyMMddHHmmss)-Azure-App-Expiration-Summary.txt"
$WarningDays = "31" #Specify the amount of days for a warning status
#Azure Enterprise app configuration
$STR_TenantID = ""
$STR_AppID = ""
$STR_ClientSecret = ""
#Email report settings
$STR_SMTPServer = ""
$STR_SMTPServerPort = ""
$STR_SMTPUsername = ""
$STR_SMTPPassword = ""
$STR_EmailSubject= "Azure App expiration report - $(Get-Date -Format "dd-MM-yyyy")"
$STR_SMTPFromaddress = "Servicedesk ICT "
$STR_Receivers = "servicedesk@contoso.com,systemengineer1@contoso.com" #List of commaseperated emailaddresses
#endregion
#region functions
function SendMailv2 ($To,$Subject,$Body){
$SMTPClient = New-Object Net.Mail.SmtpClient($STR_SMTPServer, $STR_SMTPServerPort)
# $SMTPClient.EnableSsl = $true
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential($STR_SMTPUsername, $STR_SMTPPassword);
$SMTPMessage = New-Object System.Net.Mail.MailMessage($STR_SMTPFromaddress,$To,$Subject,$Body)
$SMTPMessage.IsBodyHTML = $true
$SMTPClient.Send($SMTPMessage)
}
function Initiate-Log {
# Get current user and session information
$username = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
$computerName = $env:COMPUTERNAME
$sessionID = $pid
$date = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
# Write log header
$logHeader = "[$date] Log initiated by $username on $computerName (Session ID: $sessionID)"
Add-Content -Path $logfilelocation\$logfilename -Value "**********************"
Add-Content -Path $logfilelocation\$logfilename -Value "LogFile initiation"
Add-Content -Path $logfilelocation\$logfilename -Value "Start time: $date"
Add-Content -Path $logfilelocation\$logfilename -Value "Username: $username"
Add-Content -Path $logfilelocation\$logfilename -Value "Machine: $computerName"
Add-Content -Path $logfilelocation\$logfilename -Value "Process ID: $sessionID"
Add-Content -Path $logfilelocation\$logfilename -Value "Script Version: $Version"
Add-Content -Path $logfilelocation\$logfilename -Value "Script Source: https://git.dcomputers.nl/Dcomputers/PowershellScripts"
Add-Content -Path $logfilelocation\$logfilename -Value "**********************"
}
function Write-Log {
[CmdletBinding()]
Param (
[Parameter(Mandatory=$true)]
[string]$Message,
[Parameter(Mandatory=$false)]
[ValidateSet("INFO", "WARNING", "ERROR")]
[string]$Level = "INFO"
)
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$logmessage = "[$timestamp] [$Level] $Message"
Add-Content -Path $logfilelocation\$logfilename -Value $logmessage
}
function Write-Summary {
[CmdletBinding()]
Param (
[Parameter(Mandatory=$true)]
[string]$Message
)
Add-Content -Path $logfilelocation\$summaryfilename -Value $Message
}
#endregion
#region prerequisites check
#Create log directory if not present and initiate logfile
if (!(test-path $logfilelocation)) {mkdir $logfilelocation}
Initiate-Log
#Check if the required Powershell Modules are available
$modules = @("Microsoft.Graph")
foreach ($module in $modules) {
if (!(Get-Module -Name $module -ListAvailable)) {
Write-Host "The $module module is not installed. Please install it and try again."
Write-Log -Message "The $module module is not installed. Please install it and try again." -Level ERROR
exit 1
}
}
#Setup MSGraph connection
$ClientSecretPass = ConvertTo-SecureString -String $STR_ClientSecret -AsPlainText -Force
$ClientSecretCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $STR_AppID, $ClientSecretPass
Connect-MgGraph -TenantId $STR_TenantID -ClientSecretCredential $ClientSecretCredential -NoWelcome
Write-Log -Message "Connected to MsGraph API" -Level INFO
#endregion
#region execute script
#Collect all app Registration information
$AzureADApps = Get-MgApplication -all | Sort-Object DisplayName
$AppClientSecretsDetails = @() #Initiate the array to store the collected information
$AppCertificateDetails = @() #Initiate the array to store the collected information
foreach ($App in $AzureADApps) {
#Script should be extended to also include Certificates, preparations are already made.
#Collect Client Secret details if available
if ($null -ne $App.PasswordCredentials) {
foreach ($PasswordCredential in $App.PasswordCredentials) {
#Calculate remaining days
$RemainingDays = New-TimeSpan -Start $(Get-Date) -End $PasswordCredential.EndDateTime
$DaysRemaining = $RemainingDays.Days
switch ($DaysRemaining) {
{$_ -le '0'} {$CalculatedStatus = "ERROR"}
{$_ -le $WarningDays} {$CalculatedStatus = "WARNING"}
Default {$CalculatedStatus = "OK"}
}
$AppClientSecretsDetails += [PSCustomObject]@{
AppDisplayName = $App.DisplayName
SecretName = $PasswordCredential.Displayname
Enddate = $PasswordCredential.EndDateTime
DaysRemaining = $DaysRemaining
Status = $CalculatedStatus
}
}
}
#Collect Client Secret details if available
if ($null -ne $App.KeyCredentials) {
foreach ($KeyCredential in $App.KeyCredentials) {
#Calculate remaining days
$RemainingDays = New-TimeSpan -Start $(Get-Date) -End $KeyCredential.EndDateTime
$DaysRemaining = $RemainingDays.Days
switch ($DaysRemaining) {
{$_ -le '0'} {$CalculatedStatus = "ERROR"}
{$_ -le $WarningDays} {$CalculatedStatus = "WARNING"}
Default {$CalculatedStatus = "OK"}
}
$AppCertificateDetails += [PSCustomObject]@{
AppDisplayName = $App.DisplayName
CertificateName = $KeyCredential.Displayname
Enddate = $KeyCredential.EndDateTime
DaysRemaining = $DaysRemaining
Status = $CalculatedStatus
}
}
}
}
#endregion
# Create an HTML report
$htmlReport = @"
Azure App expiration report - $(Get-Date -Format "dd-MM-yyyy - HH:mm")
Script version: $Version
"@
if ("" -ne $AppClientSecretsDetails) { $htmlReport += @"
App Registration Secrets Overview
| App DisplayName |
Secret Name |
Enddate |
Days Remaining |
Status |
"@
foreach ($AppClientSecretsDetail in $AppClientSecretsDetails) {
$htmlReport += @"
| $($AppClientSecretsDetail.AppDisplayName) |
$($AppClientSecretsDetail.SecretName) |
$($AppClientSecretsDetail.Enddate) |
$($AppClientSecretsDetail.DaysRemaining) |
$(switch ($AppClientSecretsDetail.Status) {
'ERROR' {"$($AppClientSecretsDetail.Status) | "}
'WARNING' {"$($AppClientSecretsDetail.Status) | "}
default {"$($AppClientSecretsDetail.Status) | "}
} )
"@
}
$htmlReport += "
"
}
if ("" -ne $AppCertificateDetails) { $htmlReport += @"
App Registration Certificates Overview
| App DisplayName |
Certificate Name |
Enddate |
Days Remaining |
Status |
"@
foreach ($AppCertificateDetail in $AppCertificateDetails) {
$htmlReport += @"
| $($AppCertificateDetail.AppDisplayName) |
$($AppCertificateDetail.CertificateName) |
$($AppCertificateDetail.Enddate) |
$($AppCertificateDetail.DaysRemaining) |
$(switch ($AppCertificateDetail.Status) {
'ERROR' {"$($AppCertificateDetail.Status) | "}
'WARNING' {"$($AppCertificateDetail.Status) | "}
default {"$($AppCertificateDetail.Status) | "}
} )
"@
}
$htmlReport += "
"
}
$htmlReport += @"
This is an automated report.
"@
#endregion
#region send reports and generate summary report
# Send the report via email
$Status = "OK"
switch ($licenseUsageData | Select-Object -ExpandProperty LicenseStatus) {
{ $_ -contains "ERROR" } { $Status = "ERROR"; break }
{ $_ -contains "WARNING" } { $Status = "WARNING"; break }
}
if ($Status -ne "OK") {
$subject = "$($Status): $STR_EmailSubject"
}
else {
$subject = "$STR_EmailSubject"
}
$body = $htmlReport
SendMailv2 -To $STR_Receivers -Subject $subject -Body $body
# write summary
Write-Summary "Azure App Secrets expiration report Summary:"
Write-Summary "---------------------------"
Write-Summary "Report date: $(Get-Date -Format "dd-MM-yyy HH:mm:ss")"
if ("" -ne $AppClientSecretsDetails) {
Write-Summary "App Client Secrets"
foreach ($AppClientSecretsDetail in $AppClientSecretsDetails) {
Write-Summary "******************"
Write-Summary "App DisplayName: $($AppClientSecretsDetail.AppDisplayName)"
Write-Summary "Secret Name: $($AppClientSecretsDetail.SecretName)"
Write-Summary "Enddate: $($AppClientSecretsDetail.Enddate)"
Write-Summary "Days Remaining: $($AppClientSecretsDetail.DaysRemaining)"
Write-Summary "Status: $($AppClientSecretsDetail.Status)"
}
}
if ("" -ne $AppCertificateDetails) {
Write-Summary "App Client Secrets"
foreach ($AppCertificateDetail in $AppCertificateDetails) {
Write-Summary "******************"
Write-Summary "App DisplayName: $($AppCertificateDetail.AppDisplayName)"
Write-Summary "Certificate Name: $($AppCertificateDetail.CertificateName)"
Write-Summary "Enddate: $($AppCertificateDetail.Enddate)"
Write-Summary "Days Remaining: $($AppCertificateDetail.DaysRemaining)"
Write-Summary "Status: $($AppCertificateDetail.Status)"
}
}
Write-Summary "---------------------------"
#endregion