ADDSAuditTasks.psm1

#Region '.\Private\Export-AuditCSVtoZip.ps1' 0
function Export-AuditCSVtoZip {
    [CmdletBinding()]
    param (
        [PSCustomObject[]]$Export,
        [string]$csv,
        [string]$zip
    )
    process {

            Write-TSLog "The $($script:MyInvocation.MyCommand.Name -replace '\..*') Export was successful. There are $($Export.Count) accounts listed with the following properties: "
            ($Export | Get-Member | Where-Object { $_.membertype -eq "NoteProperty" }).Name | Write-TSLog
            Write-TSLog "Exporting CSV to path: $csv"
            try {
                $Export | Export-CSV -Path $csv -NoTypeInformation -ErrorVariable ExportErr -ErrorAction Stop
            }
            catch {
                Write-TSLog "The CSV export failed with error: "
                Write-TSLog -End
                Write-TSLog -LogErrorEnd
                throw $ExportErr
            }
            Write-TSLog "Compressing file: $csv to destination zip file: $zip"
            try {
                Compress-Archive -Path $csv -DestinationPath $zip -Verbose -ErrorVariable ZipErr -ErrorAction Stop
            }
            catch {
                Write-TSLog "Failed compressing file: $csv to destination zip file: $zip with error: "
                Write-TSLog -End
                throw $ZipErr
            }
            Write-TSLog "Removing CSV $csv from directory."
            try {
                Remove-Item $csv -Force -ErrorVariable CSVDeleteErr -ErrorAction Stop
            }
            catch {
                Write-TSLog "Failed to remove CSV file: $csv"
                Write-TSLog -LogError -LogErrorVar $CSVDeleteErr
            }
            Write-TSLog "Removed CSV `n$csv`nfrom directory."
    }
}
#EndRegion '.\Private\Export-AuditCSVtoZip.ps1' 42
#Region '.\Private\Get-ADGroupMemberof.ps1' 0
function Get-ADGroupMemberof {
    [CmdletBinding()]
    param (
        [string]$SamAccountName
    )
    process {
        $GroupStringArray = ((Get-ADuser -Identity $SamAccountName -Properties memberof).memberof | Get-ADGroup | Select-Object name | Sort-Object name).name
        $GroupString = $GroupStringArray -join " | "
        return $GroupString
    }
}
#EndRegion '.\Private\Get-ADGroupMemberof.ps1' 12
#Region '.\Private\Get-TimeStamp.ps1' 0
function Get-TimeStamp {
    return "[{0:yyyy/MM/dd} {0:HH:mm:ss}]" -f (Get-Date)
}



#EndRegion '.\Private\Get-TimeStamp.ps1' 7
#Region '.\Private\Initialize-AuditBeginBlock.ps1' 0
function Initialize-AuditBeginBlock {
<#
    .SYNOPSIS
    This is a sample Private function only visible within the module.
 
    .DESCRIPTION
    This sample function is not exported to the module and only return the data passed as parameter.
 
    .EXAMPLE
    $null = Initialize-AuditBeginBlock -PrivateData 'NOTHING TO SEE HERE'
 
    .PARAMETER PrivateData
    The PrivateData parameter is what will be returned without transformation.
 
    #>

    [cmdletBinding()]
    [OutputType([string])]
    param(
        [Parameter(
            ValueFromPipeline = $true
        )]
        [string]$AttachementFolderPath = "C:\temp\ADDSAuditTasks",
        [Parameter(
            ValueFromPipelineByPropertyName = $true
        )]
        [bool]$SendMailMessage,
        [Parameter(
            ValueFromPipelineByPropertyName = $true
        )]
        [bool]$Clean
    )


    process {
        # Create Directory Path
        $AttachementFolderPathCheck = Test-Path -Path $AttachementFolderPath
        If (!($AttachementFolderPathCheck)) {
            Try {
                # If not present then create the dir
                New-Item -ItemType Directory $AttachementFolderPath -Force -ErrorAction Stop
            }
            Catch {
                Write-TSLog -Begin
                Write-TSLog "Directory: $AttachementFolderPath was not created."
                Write-TSLog -LogErrorEnd
                throw
            }
        }
        # Begin Logging to $script:Logs
        Write-TSLog -Begin
        $script:LogOutputPath = "$AttachementFolderPath\$((Get-Date).ToString("yyyy-MM-dd-hh.mm.ss"))_ADDSAuditlog.log"
        Write-TSLog "Log output path: $LogOutputPath"
        # If not Clean
        if (!($Clean)) {
            # 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 -ErrorAction Stop
            }
            catch {
                Write-TSLog "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`"."
                Write-TSLog -LogErrorEnd
                throw
            }
        }
        # If SendMailMessage
        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 -ErrorAction Stop
            }
            catch {
                # End run and log to file.
                Write-TSLog "The Module Was not installed. Use `"Save-Module -Name Send-MailKitMessage -AllowPrerelease -Path C:\temp`" on another Windows Machine."
                Write-TSLog -End
                throw
            }
        }
        return $LogOutputPath
    }
}

#EndRegion '.\Private\Initialize-AuditBeginBlock.ps1' 90
#Region '.\Private\Initialize-AuditEndBlock.ps1' 0
function Initialize-AuditEndBlock {
    <#
    .SYNOPSIS
    This is a sample Private function only visible within the module.
 
    .DESCRIPTION
    This sample function is not exported to the module and only return the data passed as parameter.
 
    .EXAMPLE
    $null = Initialize-AuditEndBlock -PrivateData 'NOTHING TO SEE HERE'
 
    .PARAMETER PrivateData
    The PrivateData parameter is what will be returned without transformation.
 
    #>

    [cmdletBinding()]
    param
    (
        [string]$smtpServer,
        [int]$port,
        [string]$username,
        #[switch]$ssl,
        [string]$from,
        [string]$to,
        #[string]$subject = "$($script:MyInvocation.MyCommand.Name -replace '\..*') report ran for $($env:USERDNSDOMAIN).",
        [string]$attachementfolderpath,
        #[string]$body,
        [securestring]$Password,
        [string]$Function,
        [string]$FunctionApp,
        [string]$ApiToken,
        [string]$zip,
        [bool]$Clean,
        [bool]$LocalDisk,
        [bool]$SendMailMessage
    )

    process {
        Write-TSLog "The Value of Clean is $Clean."
        if ($Clean) {
            Write-TSLog "Removing Send-MailKitMessage Module"
            try {
                # Remove Modules
                Remove-Module -Name "Send-MailKitMessage" -Force -Confirm:$false
            }
            catch {
                Write-TSLog "Error removing Send-MailKitMessage Module"
                Write-TSLog -LogError
            }
            Write-TSLog "Uninstalling Send-MailKitMessage Module"
            try {
                # Uninstall Modules
                Uninstall-Module -Name "Send-MailKitMessage" -AllowPrerelease -Force -Confirm:$false
            }
            catch {
                Write-TSLog -LogError
                if (Get-Module -Name Send-MailKitMessage -ListAvailable) {
                    Write-TSLog "Error uninstalling Send-MailKitMessage Module"
                }
            }
            Write-TSLog "Removing directories and files in: "
            Write-TSLog "$AttachementFolderPath"
            try {
                Remove-Item -Path $AttachementFolderPath -Recurse -Force
            }
            catch {
                Write-TSLog "Directory Cleanup error!"
                Write-TSLog -LogError
                throw
            }
            Write-TSLog -End
            Write-TSLog -LogOutputPath C:\temp\ADDSAuditTaskCleanupLogs.log
        }
        else {
            if ($SendMailMessage) {
                if ($Password) {
                    <#
                    Send Attachement using O365 email account and password.
                    Must exclude from conditional access legacy authentication policies.
                    #>

                    Write-Logs "Account: $Username, sending email to $to from User $From using Port $Port, through relay $SMTPServer, using SSL and a Password."
                    Write-Logs "Logs included in body"
                    Write-Logs -End
                    Send-AuditEmail -smtpServer $SMTPServer -port $Port -username $Username `
                        -body $script:Logs -pass $Password -from $From -to $to -attachmentfilePath "$zip" -ssl
                    $Password.Dispose()
                    Remove-Item $zip -Force
                } # End if
                else {
                    Write-Logs "Account: $Username, sending email to $to from User $From using a no password over port $Port through relay $SMTPServer, using ssl."
                    Write-Logs "Logs included in body"
                    Write-Logs -End
                    Send-AuditEmail -smtpServer $SMTPServer -port $Port -username $Username `
                        -body $script:Logs -from $From -to $to -attachmentfilePath "$zip" -ssl
                    Remove-Item $zip -Force
                }
            }
            elseif ($FunctionApp) {
                <#
                Send Attachement using O365 email account and Keyvault retrived password.
                Must exclude email account from conditional access legacy authentication policies.
                #>

                Write-Logs "Account: $Username, sending email to $to from User $From using Function App $FunctionApp, using function $function over port $Port through relay $SMTPServer, using ssl."
                Write-Logs "Logs included in body"
                Write-Logs -End
                Send-AuditEmail -smtpServer $SMTPServer -port $Port -username $Username `
                    -body $script:Logs -Function $Function -FunctionApp $FunctionApp -token $ApiToken -from $from -to $to -attachmentfilePath "$zip" -ssl
            }
            elseif ($LocalDisk) {
                #Confirm output path to console.
                Write-TSLog  "The ADDSAuditTask archive have been saved to: "
                Write-TSLog  "$zip"
                Write-TSLog -End
                Write-TSLog -LogOutputPath $LogOutputPath
            }
        }
    }
}

#EndRegion '.\Private\Initialize-AuditEndBlock.ps1' 120
#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 = "$($script:MyInvocation.MyCommand.Name -replace '\..*') report ran for $($env:USERDNSDOMAIN).",
            [string]$attachmentfilePath,
            [string]$body,
            [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 '.\Private\Write-TSLog.ps1' 0
function Write-TSLog {
    <#
    .SYNOPSIS
    This is a sample Private function only visible within the module.
    .DESCRIPTION
    This sample function is not exported to the module and only return the data passed as parameter.
    .EXAMPLE
    $null = Write-Logs -PrivateData 'NOTHING TO SEE HERE'
    .PARAMETER PrivateData
    The PrivateData parameter is what will be returned without transformation.
#>

    [CmdletBinding(DefaultParameterSetName = 'Default')]
    [OutputType([string])]
    param(
        [Parameter(
            ValueFromPipeline = $true,
            ValueFromPipelineByPropertyName = $true,
            Mandatory = $true,
            ParameterSetName = 'Default',
            Position = 0
        )]
        [String[]]$LogString,
        [Parameter(
            ValueFromPipelineByPropertyName = $true,
            Mandatory = $true,
            ParameterSetName = 'Begin',
            Position = 0
        )]
        [switch]$Begin,
        [Parameter(
            ValueFromPipelineByPropertyName = $true,
            Mandatory = $true,
            ParameterSetName = 'End',
            Position = 0
        )]
        [switch]$End,
        [Parameter(
            ValueFromPipelineByPropertyName = $true,
            Mandatory = $true,
            ParameterSetName = 'LogError',
            Position = 0
        )]
        [switch]$LogError,
        [Parameter(
            ValueFromPipelineByPropertyName = $true,
            Mandatory = $true,
            ParameterSetName = 'LogErrorEnd',
            Position = 0
        )]
        [switch]$LogErrorEnd,
        [Parameter(ParameterSetName = 'LogError', Position = 1)]
        [Parameter(
            ValueFromPipelineByPropertyName = $true,
            ParameterSetName = 'LogErrorEnd',
            Position = 1
        )]
        [System.Management.Automation.ErrorRecord[]]$LogErrorVar,
        [Parameter(
            ValueFromPipelineByPropertyName = $true,
            Mandatory = $true,
            ParameterSetName = 'LogToFile',
            Position = 0
        )]
        [string]$LogOutputPath
    )
    process {
        # Change the ErrorActionPreference to 'Stop'
        $ErrorActionPreference = "SilentlyContinue"
        $ModuleName = $script:MyInvocation.MyCommand.Name.ToString() -replace '\..*'
        $ModuleVer = $MyInvocation.MyCommand.Version.ToString()
        $ErrorActionPreference = "Continue"
        if ($Begin) {
            Clear-Variable Logs -Scope Script -ErrorAction SilentlyContinue
            $TSLogString = "$(Get-TimeStamp) Begin Log for Module version $ModuleVer of Module: $ModuleName `n"
            $script:Logs += $TSLogString
        }
        elseif ($End) {
            $TSLogString = "$(Get-TimeStamp) End Log for Module version $ModuleVer of Module: $ModuleName `n"
            $script:Logs += $TSLogString
            Write-Output $script:Logs
        }
        elseif ($LogError) {
            if ($LogErrorVar) {
                #$TSLogString += "$(($LogErrorVar.Exception).ToString()) `n"
                $TSLogString += "$(($LogErrorVar.Exception).ToString()) `n"
            }
            else {
                $TSLogString = "$(($script:Error[0].Exception).ToString()) `n"
            }
            $script:Logs += $TSLogString
        }
        elseif ($LogErrorEnd) {
            if ($LogErrorVar) {
                $TSLogString = "$(Get-TimeStamp) An Error Occured. The Error Variable was: `n"
                $script:Logs += $TSLogString
                $TSLogString += "$(($LogErrorVar.Exception).ToString()) `n"
                $script:Logs += $TSLogString
                $TSLogString = "$(Get-TimeStamp) End Log for Module version $ModuleVer of Module: $ModuleName `n"
                $script:Logs += $TSLogString
                $TSLogString = "$(Get-TimeStamp) ErrorLog output to 'C:\temp\ADDSAuditTasksErrors.log' `n"
                $script:Logs += $TSLogString
            }
            else {
                $TSLogString = "$(Get-TimeStamp) An Error Occured. The exception was: `n"
                $script:Logs += $TSLogString
                $TSLogString = "$(($Error[0].Exception).ToString()) `n"
                $script:Logs += $TSLogString
            }
            Write-Output $script:Logs
            $script:Logs | Out-File "C:\temp\ADDSAuditTasksErrors.log" -Encoding utf8 -Append -Force
        }
        elseif ($LogOutputPath) {
            $script:Logs | Out-File $LogOutputPath -Encoding utf8 -Append -Force
            Write-Output "Logs saved to $LogOutputPath"
        }
        else {
            $TSLogString = "$(Get-TimeStamp) $logstring `n"
            $script:Logs += $TSLogString
        }
    }
}
#EndRegion '.\Private\Write-TSLog.ps1' 122
#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
    .EXAMPLE
        PS C:\> Get-ADDSActiveAccountAudit -Clean -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 ADDSAccountIsNotEnabled
        Defaults to not being set.
        Choose to search for disabled Active Directory Users.
    .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.
    .PARAMETER SMTPServer
        Defaults to Office 365 SMTP relay. Enter optional relay here.
    .PARAMETER Port
        SMTP Port to Relay. Ports can be: "993", "995", "587", or "25"
    .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: (Read-Host -AsSecureString) as in Examples.
        May be omitted.
    .PARAMETER To
        Recipient of the attachment outputs.
    .PARAMETER From
        Defaults to the same account as $UserName unless the parameter is set.
        Ensure the Account has delegated access to send on behalf for the $From account.
    .PARAMETER Clean
        Remove installed modules during run. Remove local files if not a LocalDisk run.
    .NOTES
        Can take password as input into secure string using (Read-Host -AsSecureString).
        #>

    [CmdletBinding(DefaultParameterSetName = 'LocalDisk', HelpURI = "https://criticalsolutionsnetwork.github.io/ADDSAuditTasks/#Get-ADDSActiveAccountAudit")]
    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 = 'Copy Paste the following: $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(
            Mandatory = $true,
            ParameterSetName = 'Clean',
            HelpMessage = 'Clean Modules and output path',
            Position = 0
        )]
        [switch]$Clean
    )
    Begin {
        try {
            Initialize-AuditBeginBlock -AttachementFolderPath $attachementfolderpath  -SendMailMessage $SendMailMessage -Clean $Clean -ErrorVariable InitBeginErr -ErrorAction Stop
        }
        catch {
            Write-TSLog "Begin Block failed to initialize. `n $InitBeginErr"
            Write-TSLog -End
            throw
        }
        if ($ADDSAccountIsNotEnabled) {
            $Enabled = $false
        }
        else {
            $Enabled = $true
        }
    }
    Process {
        if (!($Clean)) {
            $time90 = (Get-Date).Adddays( - (90))
            $time60 = (Get-Date).Adddays( - (60))
            $time30 = (Get-Date).Adddays( - (30))
            # Establish timeframe to review.
            $time = (Get-Date).Adddays( - ($DaysInactive))
            # Add Datetime to filename
            $csvFileName = "$attachementfolderpath\$($MyInvocation.MyCommand.Name -replace '\..*')_$($env:USERDNSDOMAIN).$((Get-Date).ToString('yyyy-MM-dd.hh.mm.ss'))"
            # Create FileNames
            $csv = "$csvFileName.csv"
            $zip = "$csvFileName.zip"
            Write-TSLog "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.

            # GetActiveUsers
            Get-aduser -Filter { LastLogonTimeStamp -lt $time -and Enabled -eq $Enabled } -Properties `
                GivenName, Surname, Mail, UserPrincipalName, Title, Description, Manager, lastlogontimestamp, samaccountname, DistinguishedName `
            | Select-Object `
            @{N = 'UserName'; E = { $_.samaccountname } }, `
            @{N = 'FirstName'; E = { $_.GivenName } }, `
            @{N = 'LastName'; E = { $_.Surname } }, `
            @{N = 'UPN'; E = { $_.UserPrincipalName } }, `
            @{N = "Last Sign-in"; E = { ([DateTime]::FromFileTime($_.lastLogonTimestamp)) } }, `
                Enabled, `
            @{Label            = 'Last Seen?'; `
                    Expression = {
                    switch (([DateTime]::FromFileTime($_.lastLogonTimestamp))) {
                        # Over 90 Days
                        { ($_ -lt $time90) } { '90 Days'; break }
                        # Over 60 Days
                        { ($_ -lt $time60) } { '60 Days'; break }
                        # Over 90 Days
                        { ($_ -lt $time30) } { '30 Days'; break }
                        default { 'Recently' }
                    }
                }
            }, `
            @{N = 'OrgUnit'; E = { $_.DistinguishedName -replace '^.*?,(?=[A-Z]{2}=)' } }, `
                Title, Manager, Department, "Access Required?", "Need Mailbox?" -OutVariable Export -ErrorVariable ExportErr | Out-Null
            try {
                Export-AuditCSVtoZip -Export $Export -csv $csv -zip $zip -ErrorAction Stop -ErrorVariable ExportAuditCSVZipErr
            }
            catch {
                Write-TSLog -LogErrorEnd -LogErrorVar $ExportAuditCSVZipErr
                throw $ExportAuditCSVZipErr
            }
        } # End If Clean Region
    } ## End Process Region
    End {
        try {
            Initialize-AuditEndBlock -SendMailMessage $SendMailMessage -smtpServer $SMTPServer -port $Port -username $username -from $from -to $to -subject $subject `
                -attachementfolderpath $attachementfolderpath -body $body -Password $Password -Function $function -FunctionApp $FunctionApp `
                -ApiToken $ApiToken -zip $zip -LocalDisk $LocalDisk -Clean $Clean -ssl -ErrorVariable InitEndErr -ErrorAction Stop
        }
        catch {
            Write-TSLog "Begin Block failed to initialize."
            Write-TSLog -LogErrorEnd -LogErrorVar $InitEndErr
            throw $InitEndErr
        }
        # Clear Variables
        Clear-Variable -Name "Function", "FunctionApp", "ApiToken"
    }
}
#EndRegion '.\Public\Get-ADDSActiveAccountAudit.ps1' 254
#Region '.\Public\Get-ADDSDepartedUsersAudit.ps1' 0
function Get-ADDSDepartedUsersAudit {
    <#
    .SYNOPSIS
        Active Directory Departed Users 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-ADDSDepartedUsersAudit -LocalDisk -Verbose
    .EXAMPLE
        PS C:\> Get-ADDSDepartedUsersAudit -WildCardIdentifier "**" -SendMailMessage -SMTPServer $SMTPServer -UserName "helpdesk@domain.com" -Password (Read-Host -AsSecureString) -To "support@domain.com" -Verbose
    .EXAMPLE
        PS C:\> Get-ADDSDepartedUsersAudit -WildCardIdentifier -FunctionApp $FunctionApp -Function $Function -SMTPServer $SMTPServer -UserName "helpdesk@domain.com" -To "support@domain.com" -Verbose
    .EXAMPLE
        PS C:\> Get-ADDSActiveAccountAudit -Clean -Verbose
    .PARAMETER LocalDisk
        Only output data to local disk.
    .PARAMETER AttachementFolderPath
        Default path is C:\temp\Get-ADDSDepartedUsersAuditLogs.
        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 WildCardIdentifier
        Name wildcard appended to user account.
    .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.
    .PARAMETER SMTPServer
        Defaults to Office 365 SMTP relay. Enter optional relay here.
    .PARAMETER Port
        SMTP Port to Relay. Ports can be: "993", "995", "587", or "25"
    .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: (Read-Host -AsSecureString) as in Examples.
        May be omitted.
    .PARAMETER To
        Recipient of the attachment outputs.
    .PARAMETER From
        Defaults to the same account as $UserName unless the parameter is set.
        Ensure the Account has delegated access to send on behalf for the $From account.
    .PARAMETER Clean
        Remove installed modules during run. Remove local files if not a LocalDisk run.
    .NOTES
        Can take password as input into secure string using (Read-Host -AsSecureString).
        #>

    [CmdletBinding(DefaultParameterSetName = 'LocalDisk' , HelpURI = "https://criticalsolutionsnetwork.github.io/ADDSAuditTasks/#Get-ADDSDepartedUsersAudit")]
    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\ADDSDepartedUsersAuditLogs",
        [Parameter(ParameterSetName = 'FunctionApp')]
        [Parameter(ParameterSetName = 'SendMailMessage')]
        [Parameter(
            ParameterSetName = 'LocalDisk',
            HelpMessage = 'Name filter attached to users.',
            ValueFromPipelineByPropertyName = $true
        )]
        [string]$WildCardIdentifier,
        [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 = 'Copy Paste the following: $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(
            Mandatory = $true,
            ParameterSetName = 'Clean',
            HelpMessage = 'Clean Modules and output path',
            Position = 0
        )]
        [switch]$Clean
    )
    begin {

        try {
            Initialize-AuditBeginBlock -AttachementFolderPath $attachementfolderpath  -SendMailMessage $SendMailMessage -Clean $Clean -ErrorVariable InitBeginErr -ErrorAction Stop
        }
        catch {
            Write-TSLog "Begin Block failed to initialize. `n $InitBeginErr"
            Write-TSLog -End
            throw
        }

    }
    process {
        if (!($Clean)) {
            $time90 = (Get-Date).Adddays( - (90))
            $time60 = (Get-Date).Adddays( - (60))
            $time30 = (Get-Date).Adddays( - (30))
            # Add Datetime to filename
            $csvFileName = "$attachementfolderpath\$($MyInvocation.MyCommand.Name -replace '\..*')_Export_$($env:USERDNSDOMAIN).$((Get-Date).ToString('yyyy-MM-dd.hh.mm.ss'))"
            # Create FileNames
            $csv = "$csvFileName.csv"
            $zip = "$csvFileName.zip"
            Write-TSLog "Searching for users appended with:`"$WildCardIdentifier`" in Active Directory."
            # Audit Script with export to csv and zip.
            # Get ad user with Name String Filter
            $WildCardIdentifierstring = '*' + $WildCardIdentifier + '*'
            Get-ADUser -Filter { Name -like $WildCardIdentifierstring } -Properties `
                GivenName, Surname, Mail, UserPrincipalName, Title, Description, Manager, lastlogontimestamp, samaccountname, DistinguishedName | `
                Select-Object `
            @{N = 'UserName'; E = { $_.samaccountname } }, `
            @{N = 'FirstName'; E = { $_.GivenName } }, `
            @{N = 'LastName'; E = { $_.Surname } }, `
            @{N = 'UPN'; E = { $_.UserPrincipalName } }, `
            @{N = "Last Sign-in"; E = { ([DateTime]::FromFileTime($_.lastLogonTimestamp)) } }, `
            @{Label            = 'Last Seen?'; `
                    Expression = {
                    switch (([DateTime]::FromFileTime($_.lastLogonTimestamp))) {
                        # Over 90 Days
                        { ($_ -lt $time90) } { 'Over 90 Days ago'; break }
                        # Over 60 Days
                        { ($_ -lt $time60) } { 'Over 60 Days ago'; break }
                        # Over 90 Days
                        { ($_ -lt $time30) } { 'Over 30 Days ago'; break }
                        default { 'Recently' }
                    }
                }
            }, `
            @{N = 'OrgUnit'; E = { $_.DistinguishedName -replace '^.*?,(?=[A-Z]{2}=)' } }, `
                Title, Manager, Department, "Access Required?", "Need Mailbox?" -OutVariable Export | Out-Null

            try {
                Export-AuditCSVtoZip -Export $Export -csv $csv -zip $zip -ErrorAction Stop -ErrorVariable ExportAuditCSVZipErr
            }
            catch {
                Write-TSLog -LogErrorEnd -LogErrorVar $ExportAuditCSVZipErr
                throw $ExportAuditCSVZipErr
            }
        } # End if (!($Clean)) {...}
    } # End process region
    End {
        try {
            Initialize-AuditEndBlock -SendMailMessage $SendMailMessage -smtpServer $SMTPServer -port $Port -username $username -from $from -to $to -subject $subject `
                -attachementfolderpath $attachementfolderpath -body $body -Password $Password -Function $function -FunctionApp $FunctionApp `
                -ApiToken $ApiToken -zip $zip -LocalDisk $LocalDisk -Clean $Clean -ssl -ErrorVariable InitEndErr -ErrorAction Stop
        }
        catch {
            Write-TSLog "Begin Block failed to initialize."
            Write-TSLog -LogErrorEnd
            throw $InitEndErr
        }
        # Clear Variables
        Clear-Variable -Name "Function", "FunctionApp", "ApiToken"
    }
}
#EndRegion '.\Public\Get-ADDSDepartedUsersAudit.ps1' 239
#Region '.\Public\Get-ADDSPrivilegedAccountAudit.ps1' 0
function Get-ADDSPrivilegedAccountAudit {
    <#
    .SYNOPSIS
        Active Directory Privileged Accounts 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-ADDSPrivilegedAccountAudit -LocalDisk -Verbose
    .EXAMPLE
        PS C:\> Get-ADDSPrivilegedAccountAudit -SendMailMessage -SMTPServer $SMTPServer -UserName "helpdesk@domain.com" -Password (Read-Host -AsSecureString) -To "support@domain.com" -Verbose
    .EXAMPLE
        PS C:\> Get-ADDSPrivilegedAccountAudit -FunctionApp $FunctionApp -Function $Function -SMTPServer $SMTPServer -UserName "helpdesk@domain.com" -To "support@domain.com" -Verbose
    .EXAMPLE
        PS C:\> Get-ADDSActiveAccountAudit -Clean -Verbose
    .PARAMETER LocalDisk
        Only output data to local disk.
    .PARAMETER AttachementFolderPath
        Default path is C:\temp\ADDSPrivilegedAccountAuditLogs.
        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 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.
    .PARAMETER SMTPServer
        Defaults to Office 365 SMTP relay. Enter optional relay here.
    .PARAMETER Port
        SMTP Port to Relay. Ports can be: "993", "995", "587", or "25"
    .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: (Read-Host -AsSecureString) as in Examples.
        May be omitted.
    .PARAMETER To
        Recipient of the attachment outputs.
    .PARAMETER From
        Defaults to the same account as $UserName unless the parameter is set.
        Ensure the Account has delegated access to send on behalf for the $From account.
    .PARAMETER Clean
        Remove installed modules during run. Remove local files if not a LocalDisk run.
    .NOTES
        Can take password as input into secure string using (Read-Host -AsSecureString).
        #>

    [CmdletBinding(DefaultParameterSetName = 'LocalDisk' , HelpURI = "https://criticalsolutionsnetwork.github.io/ADDSAuditTasks/#Get-ADDSPrivilegedAccountAudit")]
    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\ADDSPrivilegedAccountAuditLogs",
        [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 = 'Copy Paste the following: $Password = (Read-Host -AsSecureString)',
            ValueFromPipelineByPropertyName = $true
        )]
        [securestring]$Password,
        [Parameter(ParameterSetName = 'FunctionApp')]
        [Parameter(
            ParameterSetName = 'SendMailMessage',
            HelpMessage = 'Enter the port number 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(
            Mandatory = $true,
            ParameterSetName = 'Clean',
            HelpMessage = 'Clean Modules and output path',
            Position = 0
        )]
        [switch]$Clean
    )
    begin {

        try {
            Initialize-AuditBeginBlock -AttachementFolderPath $attachementfolderpath  -SendMailMessage $SendMailMessage -Clean $Clean -ErrorVariable InitBeginErr -ErrorAction Stop
        }
        catch {
            Write-TSLog "Begin Block failed to initialize. `n $InitBeginErr"
            Write-TSLog -End
            throw
        }


    } # End begin
    process {
        if (!($Clean)) {
            $csvFileName = "$attachementfolderpath\$($MyInvocation.MyCommand.Name -replace '\..*')_$($env:USERDNSDOMAIN).$((Get-Date).ToString('yyyy-MM-dd.hh.mm.ss'))"
            # Create FileNames
            $csv = "$csvFileName.csv"
            $zip = "$csvFileName.zip"
            # AD Privileged Groups Array
            $AD_PrivilegedGroups = @(
                'Enterprise Admins',
                'Schema Admins',
                'Domain Admins',
                'Administrators',
                'Cert Publishers',
                'Account Operators',
                'Server Operators',
                'Backup Operators',
                'Print Operators',
                'DnsAdmins',
                'DnsUpdateProxy',
                'DHCP Administrators'
            )










            # Time Variables
            $time90 = (Get-Date).Adddays( - (90))
            $time60 = (Get-Date).Adddays( - (60))
            $time30 = (Get-Date).Adddays( - (30))
            # Create Arrays
            $members = @()
            $ADUsers = @()
            foreach ($group in $AD_PrivilegedGroups) {
                Get-ADGroupMember -Identity $group -Recursive | `
                    Select-Object SamAccountName, Name, ObjectClass, `
                @{N = 'PriviledgedGroup'; E = { $group } }, `
                @{N = 'Enabled'; E = { (Get-ADUser -Identity $_.samaccountname).Enabled } }, `
                @{N = "LastSign-in"; E = { [DateTime]::FromFileTime((Get-ADUser -Identity $_.samaccountname -Properties lastLogonTimestamp).lastLogonTimestamp) } }, `
                @{N = 'LastSeen?'; E = {
                        switch ([DateTime]::FromFileTime((Get-ADUser -Identity $_.samaccountname -Properties lastLogonTimestamp).lastLogonTimestamp)) {
                            # Over 90 Days
                            { ($_ -lt $time90) } { 'Over 90 Days ago'; break }
                            # Over 60 Days
                            { ($_ -lt $time60) } { 'Over 60 Days ago'; break }
                            # Over 90 Days
                            { ($_ -lt $time30) } { 'Over 30 Days ago'; break }
                            default { 'Recently' }
                        }
                    }
                }, `
                @{N = 'OrgUnit'; E = { $_.DistinguishedName -replace '^.*?,(?=[A-Z]{2}=)' } }, `
                @{N = 'GroupMemberships'; E = { Get-ADGroupMemberof -SamAccountName $_.samaccountname } }, `
                    Title, Manager, Department, "AccessRequired?", "NeedMailbox?" -OutVariable members
                $ADUsers += $members
            }
            $Export = @()
            foreach ($User in $ADUsers) {
                new-object -TypeName PSCustomObject -Property @{
                    SamAccountName    = $User.SamAccountName
                    Name              = $User.Name
                    PriviledgedGroup  = $User.PriviledgedGroup
                    Enabled           = $User.Enabled
                    "LastSign-in"     = $User."LastSign-in"
                    "LastSeen?"       = $User."LastSeen?"
                    Title             = $User.Title
                    Manager           = $User.Manager
                    Department        = $User.Department
                    OrgUnit           = $User.OrgUnit
                    "AccessRequired?" = $User."AccessRequired?"
                    "NeedMailbox?"    = $User."NeedMailbox?"
                    ObjectClass       = $User.ObjectClass
                    GroupMemberships  = $User.GroupMemberships
                } -OutVariable PSObject
                $Export += $PSObject
            }
            try {
                Export-AuditCSVtoZip -Export $Export -csv $csv -zip $zip -ErrorAction Stop -ErrorVariable ExportAuditCSVZipErr
            }
            catch {
                Write-TSLog -End
                throw $ExportAuditCSVZipErr
            }
        }
    } # End process
    End {

        try {
            Initialize-AuditEndBlock -SendMailMessage $SendMailMessage -smtpServer $SMTPServer -port $Port -username $username -from $from -to $to -subject $subject `
                -attachementfolderpath $attachementfolderpath -body $body -Password $Password -Function $function -FunctionApp $FunctionApp `
                -ApiToken $ApiToken -zip $zip -LocalDisk $LocalDisk -Clean $Clean -ssl -ErrorVariable InitEndErr -ErrorAction Stop
        }
        catch {
            Write-TSLog "Begin Block failed to initialize."
            Write-TSLog -End
            throw $InitEndErr
        }
        # Clear Variables
        Clear-Variable -Name "Function", "FunctionApp", "ApiToken"
    } # End end
}
#EndRegion '.\Public\Get-ADDSPrivilegedAccountAudit.ps1' 273
#Region '.\Public\Get-ADUsersLastLogon.ps1' 0
function Get-ADUsersLastLogon {
<#
    .SYNOPSIS
    Takes samaccountname as input to retrieve most recent LastLogon from all DC's.
    .DESCRIPTION
    Takes samaccountname as input to retrieve most recent LastLogon from all DC's and output as datetime.
    .EXAMPLE
    Get-ADUsersLastLogon -SamAccountName "UserName"
    .PARAMETER SamAccountName
    The SamAccountName of the user whose lastlogon needs to be retrieved.
    #>

    [CmdletBinding(HelpURI = "https://criticalsolutionsnetwork.github.io/ADDSAuditTasks/#Get-ADUsersLastLogon")]
    [OutputType([datetime])]
    param (
        [Alias("Identity","UserName","Account")]
        [Parameter(
            Mandatory = $true,
            HelpMessage = 'Enter the SamAccountName',
            ValueFromPipeline = $true
        )]
        $SamAccountName
    )
    process {
        $dcs = Get-ADDomainController -Filter { Name -like "*" }
        $user = Get-ADUser -Identity $SamAccountName
        $time = 0
        $dt = @()
        foreach ($dc in $dcs) {
            $hostname = $dc.HostName
            $usertime = $user | Get-ADObject -Server $hostname -Properties lastLogon
            if ($usertime.LastLogon -gt $time) {
                $time = $usertime.LastLogon
            }
            $dt += [DateTime]::FromFileTime($time)
        }
        return ($dt | Sort-Object -Descending)[0]
    }
}
#EndRegion '.\Public\Get-ADUsersLastLogon.ps1' 39