ADDSActiveAccountAudit.psm1

#Region '.\Private\Send-AuditEmail.ps1' 0
function Send-AuditEmail {
    <#
    .SYNOPSIS
    This is a sample Private function only visible within the module. It uses Send-MailkitMessage
    To send email messages.
 
 
    .DESCRIPTION
    This sample function is not exported to the module and only return the data passed as parameter.
 
    .EXAMPLE
    Send-AuditEmail -smtpServer $SMTPServer -port $Port -username $Username -Function $Function -FunctionApp $FunctionApp -token $ApiToken -from $from -to $to -attachmentfilePath "$FilePath" -ssl
 
    .PARAMETER PrivateData
    The PrivateData parameter is what will be returned without transformation.
 
    #>

        param (
            [string]$smtpServer,
            [int]$port,
            [string]$username,
            [switch]$ssl,
            [string]$from,
            [string]$to,
            [string]$subject = "Active User Audit for $($env:USERDNSDOMAIN)",
            [string]$attachmentfilePath,
            [string]$body = "Audit done on $(Get-Date). Attachment file: $attachmentfilePath",
            [securestring]$pass,
            [string]$Function,
            [string]$FunctionApp,
            [string]$token
        )
        Import-Module Send-MailKitMessage
        # Recipient
        $RecipientList = [MimeKit.InternetAddressList]::new()
        $RecipientList.Add([MimeKit.InternetAddress]$to)
        # Attachment
        $AttachmentList = [System.Collections.Generic.List[string]]::new()
        $AttachmentList.Add("$attachmentfilePath")
        # From
        $from = [MimeKit.MailboxAddress]$from
        # Mail Account variable
        $User = $username
        if ($pass) {
            # Set Credential to $Password parameter input.
            $Credential = `
            [System.Management.Automation.PSCredential]::new($User, $pass)
        }
        elseif ($FunctionApp) {
            $url = "https://$($FunctionApp).azurewebsites.net/api/$($Function)"
            # Retrieve credentials from function app url into a SecureString.
            $a, $b = (Invoke-RestMethod $url -Headers @{ 'x-functions-key' = "$token" }).split(',')
            $Credential = `
                [System.Management.Automation.PSCredential]::new($User, (ConvertTo-SecureString -String $a -Key $b.split('')) )
        }
        # Create Parameter hashtable
        $Parameters = @{
            "UseSecureConnectionIfAvailable" = $ssl
            "Credential"                     = $Credential
            "SMTPServer"                     = $SMTPServer
            "Port"                           = $Port
            "From"                           = $From
            "RecipientList"                  = $RecipientList
            "Subject"                        = $subject
            "TextBody"                       = $body
            "AttachmentList"                 = $AttachmentList
        }
        Send-MailKitMessage @Parameters
        Clear-Variable -Name "a", "b", "Credential", "token" -Scope Local -ErrorAction SilentlyContinue
    }
#EndRegion '.\Private\Send-AuditEmail.ps1' 71
#Region '.\Public\Get-ADDSActiveAccountAudit.ps1' 0
function Get-ADDSActiveAccountAudit {
    <#
    .SYNOPSIS
        Active Directory Audit with Keyvault retrieval option.
    .DESCRIPTION
        Audit's Active Directory taking "days" as the input for how far back to check for a last sign in.
    .EXAMPLE
        PS C:\> Get-ADDSActiveAccountAudit -LocalDisk -Verbose
    .EXAMPLE
        PS C:\> Get-ADDSActiveAccountAudit -SendMailMessage -SMTPServer $SMTPServer -UserName "helpdesk@domain.com" -Password (Read-Host -AsSecureString) -To "support@domain.com" -Verbose
    .EXAMPLE
        PS C:\> Get-ADDSActiveAccountAudit -FunctionApp $FunctionApp -Function $Function -SMTPServer $SMTPServer -UserName "helpdesk@domain.com" -To "support@domain.com" -Verbose
    .PARAMETER LocalDisk
        Only output data to local disk.
    .PARAMETER AttachementFolderPath
        Default path is C:\temp\ADDSActiveAccountAuditLogs.
        This is the folder where attachments are going to be saved.
    .PARAMETER DaysInactive
        Defaults to 90 days in the past.
        Specifies how far back to look for accounts last logon.
        If logon is within 90 days, it won't be included.
    .PARAMETER Enabled
        Choose to search for either enabled or disabled Active Directory Users (IE: $true or $false)
    .PARAMETER SendMailMessage
        Adds parameters for sending Audit Report as an Email.
    .PARAMETER FunctionApp
        Azure Function App Name.
    .PARAMETER Function
        Azure Function App's Function Name. Ex. "HttpTrigger1"
    .PARAMETER ApiToken
        Private Function Key only.
    .PARAMETER SMTPServer
        Defaults to Office 365 SMTP relay. Enter optional relay here.
    .PARAMETER Port
        SMTP Port to Relay
    .PARAMETER UserName
        Specify the account with an active mailbox and MFA disabled.
        Ensure the account has delegated access for Send On Behalf for any
        UPN set in the "$From" Parameter
    .PARAMETER Password
        Use this parameter to active the parameterset associated with using a clear-text
        password instead of a function URI.
    .PARAMETER To
        Recipient of the attachment outputs.
    .PARAMETER From
        Defaults to the same account as $UserName unless the parameter is set.
        The email will appear as it was sent from the UPN listed here.
        Ensure the Account stated in the $UserName has delegated access to send
        on behalf of the account you add to the $From parameter.
    .PARAMETER Clean
        Remove installed modules during run.
    .NOTES
        Can take password as input into secure string instead of URI.
        Adding the password parameter right after username when calling the function will trigger the correct parameterset.
        #>

    [CmdletBinding(DefaultParameterSetName = 'LocalDisk')]
    param (
        [Parameter(
            Mandatory = $true,
            ParameterSetName = 'LocalDisk',
            HelpMessage = 'Output to disk only',
            Position = 0
        )]
        [switch]$LocalDisk,
        [Parameter(
            Mandatory = $true,
            ParameterSetName = 'SendMailMessage',
            HelpMessage = 'Send Mail to a relay',
            Position = 0
        )]
        [switch]$SendMailMessage,
        [Parameter(
            Mandatory = $true,
            ParameterSetName = 'FunctionApp',
            HelpMessage = 'Enter the FunctionApp name',
            Position = 0
        )]
        [string]$FunctionApp,
        [Parameter(
            Mandatory = $true,
            ParameterSetName = 'FunctionApp',
            HelpMessage = 'Enter the FunctionApp Function name',
            ValueFromPipelineByPropertyName = $true,
            Position = 1
        )]
        [string]$Function,
        [Parameter(ParameterSetName = 'FunctionApp')]
        [Parameter(
            ParameterSetName = 'SendMailMessage',
            HelpMessage = 'Enter the SMTP hostname' ,
            ValueFromPipelineByPropertyName = $true
        )]
        [string]$SMTPServer = "smtp.office365.com",
        [Parameter(ParameterSetName = 'FunctionApp')]
        [Parameter(ParameterSetName = 'SendMailMessage')]
        [Parameter(
            ParameterSetName = 'LocalDisk',
            HelpMessage = 'Enter output folder path',
            ValueFromPipeline = $true
        )]
        [string]$AttachementFolderPath = "C:\temp\ADDSActiveAccountAuditLogs",
        [Parameter(ParameterSetName = 'FunctionApp')]
        [Parameter(ParameterSetName = 'SendMailMessage')]
        [Parameter(
            ParameterSetName = 'LocalDisk',
            HelpMessage = 'Active Directory User Enabled or not',
            ValueFromPipelineByPropertyName = $true
        )]
        [switch]$ADDSAccountIsNotEnabled,
        [Parameter(ParameterSetName = 'FunctionApp')]
        [Parameter(ParameterSetName = 'SendMailMessage')]
        [Parameter(
            ParameterSetName = 'LocalDisk',
            HelpMessage = 'Days back to check for recent sign in',
            ValueFromPipelineByPropertyName = $true
        )]
        [int]$DaysInactive = '90',
        [Parameter(Mandatory = $true, ParameterSetName = 'FunctionApp')]
        [Parameter(
            ParameterSetName = 'SendMailMessage',
            Mandatory = $true,
            HelpMessage = 'Enter the Sending Account UPN Ex:"user@contoso.com"',
            ValueFromPipelineByPropertyName = $true
        )]
        [ValidatePattern("[a-z0-9!#\$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#\$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?")]
        [string]$UserName,
        [Parameter(
            ParameterSetName = 'SendMailMessage',
            HelpMessage = '$Password = (Read-Host -AsSecureString)',
            ValueFromPipelineByPropertyName = $true
        )]
        [securestring]$Password,
        [Parameter(ParameterSetName = 'FunctionApp')]
        [Parameter(
            ParameterSetName = 'SendMailMessage',
            HelpMessage = 'Enter the port n
                umber for the mail relay'
,
            ValueFromPipelineByPropertyName = $true
        )]
        [ValidateSet("993", "995", "587", "25")]
        [int]$Port = 587,
        [Parameter(Mandatory = $true, ParameterSetName = 'FunctionApp')]
        [Parameter(
            ParameterSetName = 'SendMailMessage',
            Mandatory = $true,
            HelpMessage = 'Enter the recipient email address',
            ValueFromPipelineByPropertyName = $true
        )]
        [ValidatePattern("[a-z0-9!#\$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#\$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?")]
        [string]$To,
        [Parameter(ParameterSetName = 'FunctionApp')]
        [Parameter(
            ParameterSetName = 'SendMailMessage',
            HelpMessage = 'Enter the name of the sender',
            ValueFromPipelineByPropertyName = $true
        )]
        [ValidatePattern("[a-z0-9!#\$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#\$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?")]
        [string]$From = $UserName,
        [Parameter(
            Mandatory = $true,
            ParameterSetName = 'FunctionApp',
            HelpMessage = 'Enter output folder path',
            ValueFromPipelineByPropertyName = $true
        )]
        [string]$ApiToken,
        [Parameter(ParameterSetName = 'FunctionApp')]
        [Parameter(
            ParameterSetName = 'SendMailMessage',
            HelpMessage = 'Clean Modules and output path',
            ValueFromPipelineByPropertyName = $true
        )]
        [switch]$Clean

    )
    Begin {
        # Create Log Path
        $DirPath = $AttachementFolderPath
        $DirPathCheck = Test-Path -Path $DirPath
        If (!($DirPathCheck)) {
            Try {
                #If not present then create the dir
                New-Item -ItemType Directory $DirPath -Force
            }
            Catch {
                throw "Directory: $DirPath was not created."
            }
        }
        # Begin Logging
        Start-Transcript -OutputDirectory $DirPath -IncludeInvocationHeader -NoClobber
        # Import Active Directory Module
        $module = Get-Module -Name ActiveDirectory -ListAvailable
        if (-not $module) {
            Add-WindowsFeature RSAT-AD-PowerShell -IncludeAllSubFeature -Verbose -ErrorAction Stop
        }
        try {
            Import-Module "activedirectory" -Global
        }
        catch {
            throw "The Module Was not installed. Use `"Add-WindowsFeature RSAT-AD-PowerShell`" or install using server manager under `"Role Administration Tools>AD DS and AD LDS Tools>Active Directory module for Windows Powershell`"."
        }
        # If SendMailMessage Begin
        if ($SendMailMessage) {
            # Install / Import required modules.
            $module = Get-Module -Name Send-MailKitMessage -ListAvailable
            if (-not $module) {
                Install-Module -Name Send-MailKitMessage -AllowPrerelease -Scope AllUsers -Force
            }
            try {
                Import-Module "Send-MailKitMessage" -Global
            }
            catch {
                throw "The Module Was not installed. Use `"Save-Module -Name Send-MailKitMessage -AllowPrerelease -Path C:\temp`" on another Windows Machine."
            }
        }
        if ($ADDSAccountIsNotEnabled) {
            $Enabled = $false
        }
        else {
            $Enabled = $true
        }
    }
    Process {
        # Create CSV Path Prefix
        $PathPrefix = "$attachementfolderpath\AD_Export_$($env:USERDNSDOMAIN)"
        # Establish timeframe to review.
        $time = (Get-Date).Adddays( - ($DaysInactive))
        # Add Datetime to filename
        $csvFileName = "$($PathPrefix).$((Get-Date).ToString('yyyy-MM-dd.hh.mm.ss'))"
        # Create FileNames
        $csv = "$csvFileName.csv"
        $zip = "$csvFileName.zip"
        Write-Output "Searching for users who have signed in within the last $DaysInactive days, where parameter Enabled = $Enabled"
        # Audit Script with export to csv and zip. Paramters for Manager, lastLogonTimestamp and DistinguishedName normalized.
        try {
            $Export = Get-aduser -Filter { LastLogonTimeStamp -lt $time -and Enabled -eq $Enabled } -Properties `
                GivenName, Surname, Mail, UserPrincipalName, Title, OfficePhone, MobilePhone, Description, Manager, lastlogontimestamp, samaccountname, DistinguishedName   | `
                Select-Object `
            @{N = 'FirstName'; E = { $_.GivenName } }, `
            @{N = 'LastName'; E = { $_.Surname } }, `
            @{N = 'UserName'; E = { $_.samaccountname } }, `
            @{N = 'SMTP PrimaryEmail'; E = { $_.mail } }, `
            @{N = 'UPN'; E = { $_.UserPrincipalName } }, `
            @{N = 'Job Title'; E = { $_.Title } }, `
            @{N = 'Telephone'; E = { $_.OfficePhone } }, `
            @{N = 'MobilePhone'; E = { $_.MobilePhone } }, `
            @{N = 'NoteEquipment'; E = { $_.Description } }, `
            @{N = 'Manager'; E = { (Get-ADUser ($_.Manager)).name } }, `
            @{N = "Last Sign-in"; E = { [DateTime]::FromFileTime($_.lastLogonTimestamp).ToString('yyyy-MM-dd.hh.mm') } }, `
            @{N = 'OrgUnit'; E = { $($_.DistinguishedName.split(',', 2)[1]) } } -ErrorAction SilentlyContinue -ErrorVariable ADCSVGen
        }
        catch {
            throw $ADCSVGen
        }
        try {
            $Export | Export-CSV -Path "$csv" -NoTypeInformation -ErrorVariable ADCSVExport
        }
        catch {
            throw $ADCSVExport
        }
        Compress-Archive -Path "$csv" -DestinationPath "$zip"
        #Confirm output path to console.
        Write-Output "The archive have been saved to: `n"
        Write-Output "$zip"
    }
    End {
        if ($SendMailMessage) {
            if ($Password) {
                <#
                Send Attachement using O365 email account and password.
                Must exclude from conditional access legacy authentication policies.
                #>

                Send-AuditEmail -smtpServer $SMTPServer -port $Port -username $Username `
                    -pass $Password -from $From -to $to -attachmentfilePath "$zip" -ssl
            } # End if
            else {
                Send-AuditEmail -smtpServer $SMTPServer -port $Port -username $Username `
                    -from $From -to $to -attachmentfilePath "$zip" -ssl
            }
        }
        elseif ($FunctionApp) {
            <#
            Send Attachement using O365 email account and Keyvault retrived password.
            Must exclude email account from conditional access legacy authentication policies.
            #>

            Send-AuditEmail -smtpServer $SMTPServer -port $Port -username $Username `
                -Function $Function -FunctionApp $FunctionApp -token $ApiToken -from $from -to $to -attachmentfilePath "$zip" -ssl
        }
        elseif ($LocalDisk) {
            Write-Output $Export
            Write-Host "The archive have been saved to: `n" -ForegroundColor Yellow
            Write-Host "$zip" -ForegroundColor Green
        }


        if ($Clean) {
            try {
                # Remove Modules
                Remove-Module -Name "Send-MailKitMessage" -Force -Confirm:$false `
                    -ErrorAction SilentlyContinue -ErrorVariable RemoveModErr
            }
            catch {
                Write-Output $RemoveModErr -Verbose
            }
            try {
                # Uninstall Modules
                Uninstall-Module -Name "Send-MailKitMessage" -AllowPrerelease -Force -Confirm:$false `
                    -ErrorAction SilentlyContinue -ErrorVariable UninstallModErr
            }
            catch {
                Write-Output $UninstallModErr -Verbose
            }
            if (!($LocalDisk)) {
                try {
                    Remove-Item -Path $DirPathCheck -Recurse -ErrorAction SilentlyContinue -ErrorVariable DirectoryCleanError
                }
                catch {
                    throw $DirectoryCleanError
                }
            }
        }
        Clear-Variable -Name "Function", "FunctionApp", "Password", "ApiToken" -Scope Local -ErrorAction SilentlyContinue
        # End Logging
        Stop-Transcript
    }
}
#EndRegion '.\Public\Get-ADDSActiveAccountAudit.ps1' 326