2023-04-25 20:03:51 +05:30
<#
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
2024-05-27 19:07:49 +05:30
Name : Microsoft 365 password expiry reports
Description : Export Office 365 Users ’ Last Password Change Date and expiry date using MS Graph
2023-04-25 20:03:51 +05:30
website : o365reports . com
2024-05-27 19:07:49 +05:30
Version : 5.1
2023-07-17 15:59:45 +05:30
Script Highlights :
~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
2024-05-27 19:07:49 +05:30
1 . A single script allows you to generate 7 different password reports .
#.Export all users and their last password change and expiry date
#.List users with password never expiry
#.Exports password expired users
#.helps to find soon-to-expire password users
#.Helps to track recent password changers, etc
2 . Generates pwd reports for all or Licensed users alone
3 . Gnerates pwd reports for all or sign-in enabled users alone
4 . The script uses MS Graph PowerShell and installs MS Graph PowerShell SDK ( if not installed already ) upon your confirmation .
5 . It can be executed with certificate-based authentication ( CBA ) too .
6 . The script can be executed with MFA enabled accounts too
7 . Exports output to CSV
8 . The script is supports certificate-based authetication
2023-07-17 15:59:45 +05:30
2023-04-25 20:03:51 +05:30
For detailed Script execution : https : / / o365reports . com / 2020 / 02 / 17 / export-office - 365 -users -last -password -change -date -to -csv
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
#>
Param
(
[ Parameter ( Mandatory = $false ) ]
[ switch ] $PwdNeverExpires ,
[ switch ] $PwdExpired ,
[ switch ] $LicensedUserOnly ,
[ int ] $SoonToExpire ,
[ int ] $RecentPwdChanges ,
[ switch ] $EnabledUsersOnly ,
[ string ] $TenantId ,
[ string ] $ClientId ,
[ string ] $CertificateThumbprint
)
2023-07-17 15:59:45 +05:30
$MsGraphBetaModule = Get-Module Microsoft . Graph . Beta -ListAvailable
if ( $MsGraphBetaModule -eq $null )
2023-04-25 20:03:51 +05:30
{
2023-07-17 15:59:45 +05:30
Write-host " Important: Microsoft Graph Beta module is unavailable. It is mandatory to have this module installed in the system to run the script successfully. "
$confirm = Read-Host Are you sure you want to install Microsoft Graph Beta module ? [ Y] Yes [N ] No
2023-04-25 20:03:51 +05:30
if ( $confirm -match " [yY] " )
{
2023-07-17 15:59:45 +05:30
Write-host " Installing Microsoft Graph Beta module... "
Install-Module Microsoft . Graph . Beta -Scope CurrentUser -AllowClobber
Write-host " Microsoft Graph Beta module is installed in the machine successfully " -ForegroundColor Magenta
2023-04-25 20:03:51 +05:30
}
else
{
2023-07-17 15:59:45 +05:30
Write-host " Exiting. `n Note: Microsoft Graph Beta module must be available in your system to run the script " -ForegroundColor Red
2023-04-25 20:03:51 +05:30
Exit
}
}
2024-05-27 19:07:49 +05:30
Write-Host " Connecting to MS Graph PowerShell... "
2023-04-25 20:03:51 +05:30
if ( ( $TenantId -ne " " ) -and ( $ClientId -ne " " ) -and ( $CertificateThumbprint -ne " " ) )
{
Connect-MgGraph -TenantId $TenantId -AppId $ClientId -CertificateThumbprint $CertificateThumbprint -ErrorAction SilentlyContinue -ErrorVariable ConnectionError | Out-Null
if ( $ConnectionError -ne $null )
{
Write-Host $ConnectionError -Foregroundcolor Red
Exit
}
}
else
{
Connect-MgGraph -Scopes " Directory.Read.All " -ErrorAction SilentlyContinue -Errorvariable ConnectionError | Out-Null
if ( $ConnectionError -ne $null )
{
Write-Host " $ConnectionError " -Foregroundcolor Red
Exit
}
}
2024-05-27 19:07:49 +05:30
2023-04-25 20:03:51 +05:30
$UserCount = 0
$PrintedUser = 0
$Result = " "
$PwdPolicy = @ { }
#Output file declaration
2024-05-27 19:07:49 +05:30
$Location = Get-Location
$ExportCSV = " $Location \PasswordExpiryReport_ $( ( Get-Date -format yyyy-MMM -dd -ddd ` hh-mm -ss ` tt ) . ToString ( ) ) .csv "
2023-04-25 20:03:51 +05:30
#Getting Password policy for the domain
2023-07-17 15:59:45 +05:30
$Domains = Get-MgBetaDomain #-Status Verified
2023-04-25 20:03:51 +05:30
foreach ( $Domain in $Domains )
{
#Check for federated domain
if ( $Domain . AuthenticationType -eq " Federated " )
{
$PwdValidity = 0
}
else
{
$PwdValidity = $Domain . PasswordValidityPeriodInDays
if ( $PwdValidity -eq $null )
{
$PwdValidity = 90
}
}
$PwdPolicy . Add ( $Domain . Id , $PwdValidity )
}
2024-05-27 19:07:49 +05:30
Write-Host " Generating M365 users' password expiry report... " -ForegroundColor Magenta
2023-04-25 20:03:51 +05:30
#Loop through each user
2024-05-27 19:07:49 +05:30
Get-MgBetaUser -All -Property DisplayName , UserPrincipalName , LastPasswordChangeDateTime , PasswordPolicies , AssignedLicenses , AccountEnabled , SigninActivity | foreach {
2023-04-25 20:03:51 +05:30
$UPN = $_ . UserPrincipalName
$DisplayName = $_ . DisplayName
[ boolean ] $Federated = $false
$UserCount + +
2024-05-27 19:07:49 +05:30
Write-Progress -Activity " `n Processed user count: $UserCount " ` n " Currently Processing: $DisplayName "
2023-04-25 20:03:51 +05:30
#Remove external users
if ( $UPN -like " *#EXT#* " )
{
return
}
$PwdLastChange = $_ . LastPasswordChangeDateTime
$PwdPolicies = $_ . PasswordPolicies
$LicenseStatus = $_ . AssignedLicenses
2024-05-27 19:07:49 +05:30
$LastSignInDate = $_ . SignInActivity . LastSignInDateTime
#Calculate Inactive days
if ( $LastSignInDate -eq $null )
{
$LastSignInDate = " Never Logged-in "
$InactiveDays = " - "
}
else
{
$InactiveDays = ( New-TimeSpan -Start $LastSignInDate ) . Days
}
2023-04-25 20:03:51 +05:30
$Print = 0
2024-05-27 19:07:49 +05:30
2023-04-25 20:03:51 +05:30
if ( $LicenseStatus -ne $null )
{
$LicenseStatus = " Licensed "
}
else
{
$LicenseStatus = " Unlicensed "
}
if ( $_ . AccountEnabled -eq $true )
{
$AccountStatus = " Enabled "
}
else
{
$AccountStatus = " Disabled "
}
#Finding password validity period for user
$UserDomain = $UPN -Split " @ " | Select-Object -Last 1
$PwdValidityPeriod = $PwdPolicy [ $UserDomain ]
#Check for Pwd never expires set from pwd policy
if ( [ int ] $PwdValidityPeriod -eq 2147483647 )
{
$PwdNeverExpire = $true
$PwdExpireIn = " Never Expires "
$PwdExpiryDate = " - "
$PwdExpiresIn = " - "
}
elseif ( $PwdValidityPeriod -eq 0 ) #Users from federated domain
{
$Federated = $true
$PwdExpireIn = " Insufficient data in O365 "
$PwdExpiryDate = " - "
$PwdExpiresIn = " - "
}
elseif ( $PwdPolicies -eq " none " -or $PwdPolicies -eq " DisableStrongPassword " ) #Check for Pwd never expires set from Set-MsolUser
{
$PwdExpiryDate = $PwdLastChange . AddDays ( $PwdValidityPeriod )
$PwdExpiresIn = ( New-TimeSpan -Start ( Get-Date ) -End $PwdExpiryDate ) . Days
if ( $PwdExpiresIn -gt 0 )
{
$PwdExpireIn = " Will expire in $PwdExpiresIn days "
}
elseif ( $PwdExpiresIn -lt 0 )
{
#Write-host `n $PwdExpiresIn
$PwdExpireIn = $PwdExpiresIn * ( -1 )
#Write-Host ************$pwdexpiresin
$PwdExpireIn = " Expired $PwdExpireIn days ago "
}
else
{
$PwdExpireIn = " Today "
}
}
else
{
$PwdExpireIn = " Never Expires "
$PwdExpiryDate = " - "
$PwdExpiresIn = " - "
}
#Calculating Password since last set
$PwdSinceLastSet = ( New-TimeSpan -Start $PwdLastChange ) . Days
#Filter for enabled users
if ( ( $EnabledUsersOnly . IsPresent ) -and ( $_ . AccountEnabled -eq $false ) )
{
return
}
#Filter for user with Password nerver expires
if ( ( $PwdNeverExpires . IsPresent ) -and ( $PwdExpireIn -ne " Never Expires " ) )
{
return
}
#Filter for password expired users
if ( ( $PwdExpired . IsPresent ) -and ( ( $PwdExpiresIn -ge 0 ) -or ( $PwdExpiresIn -eq " - " ) ) )
{
return
}
#Filter for licensed users
if ( ( $LicensedUserOnly . IsPresent ) -and ( $LicenseStatus -eq " Unlicensed " ) )
{
return
}
#Filter for soon to expire pwd users
if ( ( $SoonToExpire -ne " " ) -and ( ( $PwdExpiryDate -eq " - " ) -or ( $SoonToExpire -lt $PwdExpiresIn ) -or ( $PwdExpiresIn -lt 0 ) ) )
{
return
}
#Filter for recently password changed users
if ( ( $RecentPwdChanges -ne " " ) -and ( $PwdSinceLastSet -gt $RecentPwdChanges ) )
{
return
}
if ( $Federated -eq $true )
{
$PwdExpiryDate = " Insufficient data in O365 "
$PwdExpiresIn = " Insufficient data in O365 "
}
$PrintedUser + +
#Export result to csv
2024-05-27 19:07:49 +05:30
$Result = [ PSCustomObject ] @ { 'Display Name' = $_ . DisplayName ; 'User Principal Name' = $UPN ; 'Pwd Last Change Date' = $PwdLastChange ; 'Days since Pwd Last Set' = $PwdSinceLastSet ; 'Pwd Expiry Date' = $PwdExpiryDate ; 'Friendly Expiry Time' = $PwdExpireIn ; 'Days since Expiry(-) / Days to Expiry(+)' = $PwdExpiresIn ; 'License Status' = $LicenseStatus ; 'Account Status' = $AccountStatus ; 'Last Sign-in Date' = $LastSignInDate ; 'Inactive Days' = $InactiveDays }
2023-04-25 20:03:51 +05:30
$Result | Export-Csv -Path $ExportCSV -Notype -Append
}
if ( $UserCount -eq 0 )
{
Write-Host No records found
}
else
{
Write-Host " `n The output file contains " -NoNewline
Write-Host $PrintedUser users . -ForegroundColor Green
2024-05-27 19:07:49 +05:30
Write-Host ` n ~ ~ Script prepared by AdminDroid Community ~ ~ ` n -ForegroundColor Green
Write-Host " ~~ Check out " -NoNewline -ForegroundColor Green ; Write-Host " admindroid.com " -ForegroundColor Yellow -NoNewline ; Write-Host " to get access to 1800+ Microsoft 365 reports. ~~ " -ForegroundColor Green ` n ` n
2023-04-25 20:03:51 +05:30
if ( ( Test-Path -Path $ExportCSV ) -eq " True " )
{
2023-07-17 15:59:45 +05:30
Write-Host ` n " The Output file availble in: " -NoNewline -ForegroundColor Yellow ; Write-Host " $ExportCSV " ` n
2023-04-25 20:03:51 +05:30
$Prompt = New-Object -ComObject wscript . shell
$UserInput = $Prompt . popup ( " Do you want to open output file? " , ` 0 , " Open Output File " , 4 )
if ( $UserInput -eq 6 )
{
Invoke-Item " $ExportCSV "
}
}
}
2023-07-17 15:59:45 +05:30
2023-04-25 20:03:51 +05:30
Disconnect-MgGraph | Out-Null