From 0f9635840efbb6ec28e7e73e61f746fe829ff48d Mon Sep 17 00:00:00 2001 From: Ivo Oskamp Date: Thu, 19 Dec 2024 20:05:33 +0100 Subject: [PATCH] Upload files to "src/PWExpireNotification/1.0.1/Functions" --- .../Functions/Get-PWADDSExpiringPassword.ps1 | 67 +++++++++++ .../Functions/Get-PWApplicationToken.ps1 | 48 ++++++++ .../1.0.1/Functions/New-PWEmailBody.ps1 | 29 +++++ .../Functions/New-PWEmailMessagePayload.ps1 | 61 ++++++++++ .../Functions/Send-PWExpiringMailMessage.ps1 | 107 ++++++++++++++++++ 5 files changed, 312 insertions(+) create mode 100644 src/PWExpireNotification/1.0.1/Functions/Get-PWADDSExpiringPassword.ps1 create mode 100644 src/PWExpireNotification/1.0.1/Functions/Get-PWApplicationToken.ps1 create mode 100644 src/PWExpireNotification/1.0.1/Functions/New-PWEmailBody.ps1 create mode 100644 src/PWExpireNotification/1.0.1/Functions/New-PWEmailMessagePayload.ps1 create mode 100644 src/PWExpireNotification/1.0.1/Functions/Send-PWExpiringMailMessage.ps1 diff --git a/src/PWExpireNotification/1.0.1/Functions/Get-PWADDSExpiringPassword.ps1 b/src/PWExpireNotification/1.0.1/Functions/Get-PWADDSExpiringPassword.ps1 new file mode 100644 index 0000000..5755831 --- /dev/null +++ b/src/PWExpireNotification/1.0.1/Functions/Get-PWADDSExpiringPassword.ps1 @@ -0,0 +1,67 @@ +Function Get-PWADDSExpiringPassword { + [cmdletbinding()] + + [OutputType([System.Collections.Generic.List[PSCustomObject]])] + + param ( + [int]$ExpireInDays = 30, + + [scriptblock]$ADFilter, + + [switch]$IncludeAll + ) + begin { + #ToDO + # Email Attribute selection vs. current single attribute. Mail, custom attribute + # Still needs logging + } + Process { + # System Settings + $Today = Get-Date + # End System Settings + if ($PSBoundParameters.ContainsKey('ADFilter' )) { + $users = get-aduser -filter $ADFilter -Properties Name, PasswordNeverExpires, PasswordExpired, PasswordLastSet, EmailAddress + if ($PSBoundParameters.ContainsKey('IncludeAll')) { + $users = $users | Where-Object {$null -ne $PSItem.PasswordLastSet} + } + else { + $users = $users | Where-Object { ($PSItem.Enabled -eq $true) -and ($PSItem.PasswordNeverExpires -eq $false) -and ($PSItem.PasswordExpired -eq $false) } + } + } + else { + $users = Get-ADUser -filter * -Properties Name, PasswordNeverExpires, PasswordExpired, PasswordLastSet, EmailAddress + if ($PSBoundParameters.ContainsKey('IncludeAll')) { + $users = $users | Where-Object {$null -ne $PSItem.PasswordLastSet} + } + else { + $users = $users | Where-Object { ($PSItem.Enabled -eq $true) -and ($PSItem.PasswordNeverExpires -eq $false) -and ($PSItem.PasswordExpired -eq $false) } + } + } + $DefaultmaxPasswordAge = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge + + $UserCollection = [System.Collections.Generic.List[pscustomobject]]::new() + + foreach ($user in $users) { + Write-Verbose "$($user.Name)" + $PasswordPol = (Get-AduserResultantPasswordPolicy $user) + # Check for Fine Grained Password + if ($PasswordPol) { + $maxPasswordAge = ($PasswordPol).MaxPasswordAge + } + else{ + # No FGP set to Domain Default + $maxPasswordAge = $DefaultmaxPasswordAge + } + $UserCollection.Add( + [pscustomobject]@{ + Name = $user.Name + EmailAddress = $user.EmailAddress + PasswordExpiresOn = $user.PasswordLastSet + $maxPasswordAge + PasswordDaystoExpire = (New-TimeSpan -Start $Today -End ($user.PasswordLastSet + $maxPasswordAge)).Days + } + ) + } + return $UserCollection + } + end {} +} \ No newline at end of file diff --git a/src/PWExpireNotification/1.0.1/Functions/Get-PWApplicationToken.ps1 b/src/PWExpireNotification/1.0.1/Functions/Get-PWApplicationToken.ps1 new file mode 100644 index 0000000..6ad8fe2 --- /dev/null +++ b/src/PWExpireNotification/1.0.1/Functions/Get-PWApplicationToken.ps1 @@ -0,0 +1,48 @@ +function Get-PWApplicationToken { + [cmdletbinding()] + param ( + [parameter(Mandatory = $true)] + [string]$clientID, + + [parameter(Mandatory = $true)] + [string]$clientSecret, + + [parameter(Mandatory = $true)] + [ValidateSet( + 'https://graph.microsoft.com','https://graph.microsoft.us','https://dod-graph.microsoft.us' + )] + [string]$Resource, + + [parameter(Mandatory = $true)] + [string]$tenantName + ) + + + begin{ + if ($Resource -eq 'https://graph.microsoft.com') { $AADLoginURI = 'https://login.microsoftonline.com' } + elseif ($Resource -eq 'https://graph.microsoft.us') { $AADLoginURI = 'https://login.microsoftonline.us' } + elseif ($Resource -eq 'https://dod-graph.microsoft.us') { $AADLoginURI = 'https://login.microsoftonline.us' } + } + process{ + Try { + $params = @{ + Uri = "$AADLoginURI/$TenantName/oauth2/v2.0/token" + Method = "POST" + ErrorAction = "Stop" + } + $ReqTokenBody = @{ + Grant_Type = "client_credentials" + Scope = "$($Resource)/.default" + client_Id = $clientID + Client_Secret = $clientSecret + } + $TokenResponse = Invoke-RestMethod @params -Body $ReqTokenBody + return $TokenResponse.access_token + } + catch { + $_ + #[System.ApplicationException]::new("Failed to aquire token") + } + } + end{} +} \ No newline at end of file diff --git a/src/PWExpireNotification/1.0.1/Functions/New-PWEmailBody.ps1 b/src/PWExpireNotification/1.0.1/Functions/New-PWEmailBody.ps1 new file mode 100644 index 0000000..3cea58c --- /dev/null +++ b/src/PWExpireNotification/1.0.1/Functions/New-PWEmailBody.ps1 @@ -0,0 +1,29 @@ +function New-PWEmailBody { + [cmdletbinding(SupportsShouldProcess=$true)] + param ( + [string]$Subject, + [string]$Importance, + [String]$Message, + [string]$EmailAddress + ) + if ($PSCmdlet.ShouldProcess(("Subject:{0}; Message: {1}; Recipient(s):{2}" -f $Subject,$Message,$EmailAddress))) { + $body = [pscustomobject]@{ + Message = [pscustomobject]@{ + Subject = $subject + importance = $importance + Body = [pscustomobject]@{ + ContentType = "Text" + Content = $Message + } + ToRecipients = [array][pscustomobject]@{ + EmailAddress = [pscustomobject]@{ + Address = $emailaddress + } + } + } + SaveToSentItems = $false + isDraft = $false + } + return $body + } +} \ No newline at end of file diff --git a/src/PWExpireNotification/1.0.1/Functions/New-PWEmailMessagePayload.ps1 b/src/PWExpireNotification/1.0.1/Functions/New-PWEmailMessagePayload.ps1 new file mode 100644 index 0000000..29e8901 --- /dev/null +++ b/src/PWExpireNotification/1.0.1/Functions/New-PWEmailMessagePayload.ps1 @@ -0,0 +1,61 @@ +Function New-PWEmailMessagePayload { + [cmdletbinding(SupportsShouldProcess=$true)] + param ( + [parameter( + Mandatory=$true, + ParameterSetName = 'Message' + )] + [string]$TextToAdd, + + [parameter( + Mandatory=$true, + ParameterSetName = 'Message' + )] + [parameter( + Mandatory=$true, + ParameterSetName = 'Subject' + )] + [pscustomobject]$ADAccount, + + [parameter( + Mandatory=$true, + ParameterSetName = 'Message' + )] + [pscustomobject]$Signature, + + [parameter( + Mandatory=$true, + ParameterSetName = 'Subject' + )] + [String]$Subject + ) + $text = @" +Dear {0}, + +Your Password will expire {1} + +$TextToAdd + +Thanks, + +$Signature +"@ + + if ($PSCmdlet.ShouldProcess("Creating new {0}" -f $PSCmdlet.ParameterSetName)) { + + if (($ADAccount.PasswordDaystoExpire) -gt "1") { + $messageDays = "in " + "$($ADAccount.PasswordDaystoExpire)" + " days." + } + else { + $messageDays = "today." + } + if ($PSBoundParameters.ContainsKey('Signature')) { + + $outtext = ($text -f $ADAccount.Name, $messageDays) + } + elseif ($PSBoundParameters.ContainsKey('Subject')) { + $outtext = ($Subject -f $messageDays) + } + return $outtext + } +} \ No newline at end of file diff --git a/src/PWExpireNotification/1.0.1/Functions/Send-PWExpiringMailMessage.ps1 b/src/PWExpireNotification/1.0.1/Functions/Send-PWExpiringMailMessage.ps1 new file mode 100644 index 0000000..08b302c --- /dev/null +++ b/src/PWExpireNotification/1.0.1/Functions/Send-PWExpiringMailMessage.ps1 @@ -0,0 +1,107 @@ +function Send-PWExpiringMailMessage { + [cmdletbinding()] + param( + [parameter(Mandatory = $true)] + [ValidateSet( + 'https://graph.microsoft.com','https://graph.microsoft.us','https://dod-graph.microsoft.us' + )] + [string]$Resource, + + [parameter(Mandatory = $true)] + [string]$SendEmailAccount, + + [parameter(Mandatory = $True)] + [string]$Token, + + [parameter(Mandatory = $false)] + [string]$TestAddress, + + [parameter(Mandatory = $true)] + [PSCustomObject]$ADAccount, + + [parameter(Mandatory = $true)] + [string]$Signature, + + [parameter(Mandatory = $true)] + [string]$TextToAdd, + + [int]$ExpireInDaysThreshold = 30, + + [Parameter( + ParameterSetName = 'Log' + )] + [switch]$Logging, + + [Parameter( + ParameterSetName = 'Log' + )] + [string]$LogFile = "$($PWD.Path)\Expiring.csv" # ie. c:\mylog.csv + ) + begin{ + <#TODO + Update handling of logging for Notified + #> + if (!$token) { + Write-Error "No Token. Please provide a valide token" + Break + } + } + + process{ + if ($PSBoundParameters.ContainsKey('Logging')) { + # Test Log File Path + $logfilePath = (Test-Path $logFile) + if (($logFilePath) -ne "True") { + # Create CSV File and Headers + $null = New-Item $logfile -ItemType File + Add-Content $logfile "Date,Name,EmailAddress,DaystoExpire,ExpiresOn,Notified" + } + } + # If Testing Is Enabled - Email Administrator + Write-Verbose ("User Account: {0}, ExpiresOn: {1}, Days: {2} " -f $ADAccount.Name, $ADAccount.PasswordExpiresOn, $ADAccount.PasswordDaystoExpire) + if ($TestAddress) { + $emailAddress = $TestAddress + } + + # If a user has no email address listed + elseif (!($ADAccount.EmailAddress)) { + $emailAddress = $TestAddress + if (!($emailAddress)) {throw "No email address"} + } + else { $emailAddress = $ADAccount.EmailAddress } + Write-Verbose ("EmailAddress to recieve email: {0}" -f $emailAddress) + # Email Subject Set Here + $subject= New-PWEmailMessagePayload -ADAccount $ADAccount -Subject "Your password will expire {0}" + $Message = New-PWEmailMessagePayload -TextToAdd $TextToAdd -ADAccount $ADAccount -Signature $Signature + $body = New-PWEmailBody -Subject $subject -Importance 'High' -Message $Message -EmailAddress $emailAddress + + #Send the email message + if (($ADAccount.PasswordDaystoExpire -ge "0") -and ($ADAccount.PasswordDaystoExpire -le $ExpireInDaysThreshold)) { + $sent = "Yes" + # If Logging is Enabled Log Details + if ($PSBoundParameters.ContainsKey('Logging')) { + Add-Content $logfile "$([datetime]::Today.ToShortDateString()),$($ADAccount.Name),$emailaddress,$($ADAccount.PasswordDaystoExpire),$($ADAccount.PasswordExpiresOn),$sent" + } + Try { + $apiUrl = "$resource/v1.0/users/$SendEmailAccount/sendMail" + Write-Verbose $apiUrl + Write-Verbose ("Using Token: {0}" -f $Token) + $bodyson = $body | ConvertTo-Json -Depth 20 -Compress + Write-Verbose ("Payload: {0}" -f $bodyson) + Invoke-RestMethod -Headers @{Authorization = "Bearer $($token)"} -Uri $apiUrl -Body $bodyson -Method Post -ContentType 'application/json' + } + Catch { + $_ + } + } + else{ + $sent = "No" + # If Logging is Enabled Log Details + if ($PSBoundParameters.ContainsKey('Logging')) { + Add-Content $logfile "$([datetime]::Today.ToShortDateString()),$($ADAccount.Name),$emailaddress,$($ADAccount.PasswordDaystoExpire),$($ADAccount.PasswordExpiresOn),$sent" + } + } + } + + end{} +} \ No newline at end of file