Public/public.ps1

function Add-DistributionMember {

    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 05172019
 
    .DESCRIPTION
    Add a mailbox or mailboxes to a distribution group. Wildcards can be used to add the whole orginization to a distribution group.
 
    .NOTES
    Requires the microsoft exchange module.
 
    .EXAMPLE
    Add a single mailbox to a single distribution group
 
    Add-DistributionMember -Mailbox JohnD@company.com -DistributionGroup "All Employees"
 
    .EXAMPLE
    Allows shortening the command or adding multiple mailboxes with a shared name to a Distribuiton Group
 
    Add-DistributionMember -Mailbox *@company.com -DistributionGroup "All Emp*"
 
    .EXAMPLE
    Add a single mailbox to multiple Distribution Groups.
 
    Add-DistributionMember -Mailbox JohnD@company.com -DistributionGroup "All Employees,Worker Bees"
    #>


    [CmdletBinding()]

    Param (
        [Parameter(Mandatory = $true)]$Mailbox,
        [Parameter(Mandatory = $true)]$DistribuitonGroup
    )

    #Check For Admin Privleges
    Get-Elevation

    Get-Mailbox -identity $Mailbox | add-distributiongroupmember -identity $DistribuitonGroup
}

function Add-LocalAdmin {
    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 05172019
 
    .DESCRIPTION
    This function adds a local admin to the computer or server it is run from.
 
    .NOTES
    Azure AD Joined machines will require the user to first login to a computer with their domain account before adding their domain account as a local admin.
    The user logging in registers their SID so that the command is succesful.
 
    .EXAMPLE
    Adds specified domain user to the local administrators group
 
    Add-LocalAdmin -user domain\user
    #>


    [CmdletBinding()]

    Param (
        [Parameter(Mandatory = $true)]$user
    )

    #Check For Admin Privleges
    Get-Elevation

    net.exe Localgroup Administrators $user /add

}

function Clear-Arp {
    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 05292019
 
    .DESCRIPTION
    Clears the local arp table
 
    .Link
    Clear-DNSClientCache
    Get-DNSClientCache
    Get-NetIPConfiguration
    Get-NetworkStatistics
    Get-PublicIP
    Resolve-DNSName
    Test-Netconnection
    #>


    #Check For Admin Privleges
    Get-Elevation

    netsh.exe interface ip delete arpcache
}

function Connect-Office365 {

    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 05172019
 
    .DESCRIPTION
    Connect to all Office 365 Modules or just those chosen using the provided parameters
 
    .Example
    Connect-Office365 -acctName name@bigcompany.com -domainHost bigcompany -all
 
    Connects to all included office 365 modules for this function
 
    .Example
    Connect-Office365 -acctName name@bigcompany.com -skype
 
    Connects to skype and includes it mandatory parameters
 
    .Example
    Connect-Office365 -domainhost bigcompany -SharepointOnline
 
    Connects to skype and includes it mandatory parameters
 
    .Example
    Connect-Office365 -AzureAD
 
    Connects to a specific module using the available AzureAD parameter
 
    .Example
    Connect-Office365 -AzureAD -Teams
 
    Connects to multiple specified modules
 
    .Notes
    Run from the EXchange Powershell Module
 
    #Sharepoint Online Module
    The SharePoint Online Management Shell is a Windows PowerShell module that you can use to manage SharePoint Online users, sites, and site collections.
    Sharepoint Online Module https://www.microsoft.com/en-us/download/details.aspx?id=35588
 
    #Azure AD Module
    Windows Azure AD tenant-based administrative tasks such as user management, domain management and for configuring single sign-on
    Install-Module AzureAD
 
    #Microsoft Online (MSOnline) Module: aka Azure AD V1 Module
    Original Azure AD module for user management and has legacy funcitons not include with the Azure AD Module
 
    #Exchange Online Module
    Exchange Online PowerShell allows you to manage your Exchange Online settings from the command line.
    Download the Exchange Online Module from the Hybrid section of Office 365 Exchange Admin Center
 
    #Security and Compliance Module
    Office 365 Security & Compliance Center PowerShell allows you to manage your Office 365 Security & Compliance Center settings from the command line.
    Download the Exchange Online Module from the Hybrid section of Office 365 Exchange Admin Center
 
    #Skype For Business Module
    Skype For Business Module allows managing Skype for Business settings from the Command Line.
    Download and install Skype for Business Module https://www.microsoft.com/en-us/download/details.aspx?id=39366
    If bug still exists, Visual C++ 2017 x64 14.10.25008 is needed to work with this module.
 
    #Microsoft Teams Module
    Microsoft Teams Module Module allows managing Microsoft Teams settings from the Command Line.
    Install-module MicrosoftTeams
 
    #Azure AZ Module
    Azure Az Module Module allows managing Azure settings, subscriptions, VM, Resource groups, and more from the Command Line.
    Replaces Azure RM
    Install-Module -Name Az
    #>


    [CmdletBinding(SupportsShouldProcess)]
    [Alias('Connect-365')]
    Param (
        [Parameter(Mandatory = $true, ParameterSetName = "All")]
        [Parameter(Mandatory = $true, ParameterSetName = "Skype")]
        [ValidateScript( { if ( $_ -notlike "*@*.*") { throw "Acctname must be a user principal name like name@company.com" } else { $true } })]
        $AcctName,
        [Parameter(Mandatory = $true, ParameterSetName = "All")]
        [Parameter(Mandatory = $true, ParameterSetName = "Sharepoint")]
        $DomainHost,
        [Parameter(Mandatory = $true, ParameterSetName = "All")][Switch] $All,
        [Parameter(Mandatory = $true, ParameterSetName = "AzureAD")][Switch] $AzureAD,
        [Parameter(Mandatory = $true, ParameterSetName = "Sharepoint")][Switch] $SharepointOnline,
        [Parameter(Mandatory = $true, ParameterSetName = "ExchangeOnline")][Switch] $ExchangeOnline,
        [Parameter(Mandatory = $true, ParameterSetName = "SecurityandCompliance")][Switch] $SecurityandCompliance,
        [Parameter(Mandatory = $true, ParameterSetName = "Skype")][Switch] $Skype,
        [Parameter(Mandatory = $true, ParameterSetName = "Teams")][Switch] $Teams,
        [Parameter(Mandatory = $true, ParameterSetName = "Az")][Switch] $Az,
        [Parameter(Mandatory = $true, ParameterSetName = "MSOnline")][Switch] $MSOnline
    )

    if ($SharepointOnline) {
        #Sharepoint Online Module
        Import-Module Microsoft.Online.SharePoint.PowerShell -DisableNameChecking
        Write-Host "Connecting to SharePoint Online" -backgroundcolor black -foregroundcolor green
        Connect-SPOService -Url https://$DomainHost-admin.sharepoint.com
    }

    if ($AzureAD) {
        #Azure AD Module
        Write-Host "Connecting to other Azure AD Services" -backgroundcolor black -foregroundcolor green
        Connect-AzureAD
    }

    if ($MSOnline) {
        #MSonline AD Module
        Write-Host "Connecting to Microsoft Online Services" -backgroundcolor black -foregroundcolor green
        Connect-MsolService
    }

    if ($ExchangeOnline) {
        #Exchange Online Module
        Write-Host "Connecting to Exchange Online Services" -backgroundcolor black -foregroundcolor green
        Connect-EXOPSSession
    }

    if ($SecurityandCompliance) {
        #Security and Compliance Module
        Write-Host "Connecting to Exchange Online Protection and Security (aka Security and Compliance)" -backgroundcolor black -foregroundcolor green
        Connect-ippssession
    }

    if ($Skype) {
        #Skype For Business Module
        Import-Module SkypeOnlineConnector
        Write-Host "Connecting to Skype for Business Online" -backgroundcolor black -foregroundcolor green
        $sfboSession = New-CsOnlineSession -UserName $AcctName
        Import-PSSession $sfboSession
    }

    if ($Teams) {
        #Microsoft Teams Module
        Write-Host "Connecting to Microsoft Teams" -backgroundcolor black -foregroundcolor green
        Connect-MicrosoftTeams

        $SkypeRequired = Read-Host "Did you import the additionaly required skype module? Yes or No"

        if ($SkypeRequired -eq 'No') {
            #Skype For Business Module
            Import-Module SkypeOnlineConnector
            Write-Host "Connecting to Skype for Business Online" -backgroundcolor black -foregroundcolor green
            $sfboSession = New-CsOnlineSession -UserName $AcctName
            Import-PSSession $sfboSession

        }
    }

    if ($Az) {
        #Azure Az Module
        Write-Host "Connecting to Azure Az Module" -backgroundcolor black -foregroundcolor green
        Connect-AzAccount
    }

    if ($All) {
        #MSonline AD Module
        Write-Host "Connecting to Microsoft Online Services" -backgroundcolor black -foregroundcolor green
        Connect-MsolService

        #Security and Compliance Module
        Write-Host "Connecting to Exchange Online Protection and Security (aka Security and Compliance)" -backgroundcolor black -foregroundcolor green
        Connect-ippssession

        #Sharepoint Online Module
        Import-Module Microsoft.Online.SharePoint.PowerShell -DisableNameChecking
        Write-Host "Connecting to SharePoint Online" -backgroundcolor black -foregroundcolor green
        Connect-SPOService -Url https://$DomainHost-admin.sharepoint.com

        #Azure AD Module
        Write-Host "Connecting to other Azure AD Services" -backgroundcolor black -foregroundcolor green
        Connect-AzureAD

        #Exchange Online Module
        Write-Host "Connecting to Exchange Online Services" -backgroundcolor black -foregroundcolor green
        Connect-EXOPSSession

        #Skype For Business Module
        Import-Module SkypeOnlineConnector
        Write-Host "Connecting to Skype for Business Online" -backgroundcolor black -foregroundcolor green
        $sfboSession = New-CsOnlineSession -UserName $AcctName
        Import-PSSession $sfboSession

        #Microsoft Teams Module
        Write-Host "Connecting to Microsoft Teams" -backgroundcolor black -foregroundcolor green
        Connect-MicrosoftTeams

        #Azure Az Module
        Write-Host "Connecting to Azure Az Module" -backgroundcolor black -foregroundcolor green
        Connect-AzAccount
    }

    Write-Host "Going to import modules with verbose switch so all commands are available" -backgroundcolor black -foregroundcolor green
    Pause
    Get-Module | Import-Module -verbose
    Clear-Host
}

function Connect-OpenSSH {
    <#
    .SYNOPSIS
    Modified 5302019
    -Taylor Lee
 
    .DESCRIPTION
    Use this function to connect to an SSH Sesstion
 
    .EXAMPLE
    Connect using a domain account and DNS Name
 
    Connect-SSH -User "domain\username" -server "Hostname"
 
    .EXAMPLE
    Connect using a local account and ipv4
 
    Connect-SSH -User "username" -server "192.168.0.1"
 
    .NOTES
    Requires the OpenSSH client feature be installed locally and SSH enabled on the server
 
    .Link
    Enable-PSRemoting
    Enable-Remoting
    Install-SSH
    #>


    [CmdletBinding()]
    [Alias('Connect-SSH')]
    Param (
        [Parameter(Mandatory = $true)]$User,
        [Parameter(Mandatory = $true)]$Server
    )

    ssh.exe $user@$server
}

function Disable-Account {

    <#
    -Taylor Lee
    Modified 05172019
 
    .DESCRIPTION
    Disables a specified Active Directory Account
 
    .NOTES
    Requires the Active Directory Module
 
    .EXAMPLE
    Use the Samaccountname of the account being disabled
 
    Disable-ADAccount -Account JohnDoe
 
    .EXAMPLE
    Use the DistinguishedName of the account being disabled
 
    Disable-ADAccount -Account "CN=John Doe,OU=Finance,OU=UserAccounts,DC=FABRIKAM,DC=COM"
 
    .EXAMPLE
    -Use the UserPrincipalName of the account being disabled
 
    Disable-ADAccount -Account JohnD@Company.com
    #>


    [CmdletBinding()]

    Param (
        [Parameter(Mandatory = $true)]$Account
    )

    #Check For Admin Privleges
    Get-Elevation

    Import-Module ActiveDirectory

    Disable-ADAccount -Identity $Account -Confirm
}

function Disable-ShakeToMinimize {

    <#
    .Synopsis
    -Taylor Lee
    Modified 05172019
 
    .Description
    This function disables the annoying shake to minimize Windows feature
    #>


    [CmdletBinding()]
    param (
    )

    reg.exe add "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /f /v "DisallowShaking" /t reg_dword /d 1

}

function Disable-Standby {
    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 06252019
 
    .DESCRIPTION
    Disables standby, sleep, and hibernate
 
    .EXAMPLE
    Disable-Standby
    #>

    [CmdletBinding()]
    [Alias("Disable-Sleep")]
    param (
    )
    Write-Host "disabling standby" -ForegroundColor Green
    powercfg.exe -change -standby-timeout-ac 0
    powercfg.exe -change -standby-timeout-dc 0
    powercfg.exe -change -hibernate-timeout-ac 0
    powercfg.exe -change -hibernate-timeout-dc 0
    powercfg.exe -change -monitor-timeout-ac 15
    powercfg.exe -change -monitor-timeout-dc 15
    powercfg.exe -change -disk-timeout-ac 0
    powercfg.exe -change -disk-timeout-dc 0
    #Lid Close do nothing
    powercfg.exe -SETACVALUEINDEX SCHEME_CURRENT 4f971e89-eebd-4455-a8de-9e59040e7347 5ca83367-6e45-459f-a27b-476b1d01c936 000
    powercfg.exe -SETDCVALUEINDEX SCHEME_CURRENT 4f971e89-eebd-4455-a8de-9e59040e7347 5ca83367-6e45-459f-a27b-476b1d01c936 000

    #Power Button do Nothing
    powercfg.exe -setacvalueindex SCHEME_CURRENT 4f971e89-eebd-4455-a8de-9e59040e7347 7648efa3-dd9c-4e3e-b566-50f929386280 000
    powercfg.exe -setdcvalueindex SCHEME_CURRENT 4f971e89-eebd-4455-a8de-9e59040e7347 7648efa3-dd9c-4e3e-b566-50f929386280 000
    powercfg.exe -h off
    Remove-Item c:\hiberfile.sys -Force -ErrorAction SilentlyContinue
}

function Disable-Updates {

    <#
    .Synopsis
    -Taylor Lee
    Modified 05172019
 
    .DESCRIPTION
    This command disable automatic updates
    #>


    [CmdletBinding()]
    param (
    )

    #Check For Admin Privleges
    Get-Elevation

    reg.exe add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update" /v AUOptions /t REG_DWORD /d 1 /f
    net.exe stop wuauserv
    net.exe start wuauserv

}

function Enable-Account {

    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 05172019
 
    .DESCRIPTION
    Enables a specified Active Directory Account
 
    .NOTES
    Requires the Active Directory Module
 
    .EXAMPLE
    Use the Samaccountname of the account being disabled
 
     Enable-ADAccount -Account JohnD
 
    .EXAMPLE
    Use the DistinguishedName of the account being disabled
 
    Enable-ADAccount -Account "CN=John Doe,OU=Finance,OU=UserAccounts,DC=FABRIKAM,DC=COM"
 
    .EXAMPLE
    Use the UserPrincipalName of the account being disabled
 
    Enable-ADAccount -Account PJohnD@Company.com
 
    .Link
    Connect-SSH
    Enable-PSRemoting
    Install-SSH
    #>


    [CmdletBinding()]

    Param (
        [Parameter(Mandatory = $true)]$Account
    )

    Import-Module ActiveDirectory

    Enable-ADAccount -Identity $Account -Confirm
}

function Enable-Remoting {
    <#
    .Synopsis
    -Taylor Lee
    Modified 05172019
 
    .Description
    This Command will enable PowerShell Remoting on a remote PC.
 
    .NOTES
    This function requires psexec. If you do not, download it with the sysinternals suite. Add psexec to one of your enviroment variable paths.
 
    .EXAMPLE
    This will enable remoting and then prompt for credentials
 
    Enable-PSRemoting -computer PCName -username domain\username
    #>


    [CmdletBinding()]

    Param (
        [Parameter(Position = 0, Mandatory = $true)]$Computer,
        [Parameter(Position = 1, Mandatory = $false)]$Username,
        [Parameter(Position = 2, Mandatory = $false)][SecureString]$Password
    )

    #Enabling PSRemoting
    PsExec.exe \\$Computer -s winrm.cmd quickconfig -q
    PsExec.exe \\$Computer -u $Username -p $Password powershell.exe cmd /c "enable-psremoting -force"


    #Testing that PSRemoting is now enabled.
    Write-Host "If an error is presented after this point PSRemoting wasn't enabled"       -Foregroundcolor Yellow
    Test-WSMan $Computer
}

function Find-ComputersFiles {

    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 05172019
 
    .DESCRIPTION
    Discover queried files meeting a specific search parameter and output the findings to a spreadsheet.
 
    .EXAMPLE
    Searches computers listed in the text file for pst files and outputs the findings to a spreadsheet.
    (Computers should be line delimited)
 
    find-computersfiles -computers C:\computers.txt -csvout c:\results.csv -include *.pst
 
    .EXAMPLE
    Performs the same function as the first example, except it only searches the specified path and it's subfolders.
 
    find-computersfiles -computers C:\computers.txt -csvout c:\results.csv -include *.pst -path "c$\users\username\appdata\local"
    #>


    [CmdletBinding(SupportsShouldProcess)]
    Param (
        #Variable containing computers being queried
        [Parameter(Position = 0, Mandatory = $true)]$computers,
        #Variable containing output path for csv file
        [Parameter(Position = 1, Mandatory = $true)]$csvout,
        #Variable specifying search parameter
        [Parameter(Position = 2, Mandatory = $true)]$include,
        #Variable specifying search parameter
        [Parameter(Position = 3)]$Path = "c$"
    )

    #Check For Admin Privleges
    Get-Elevation

    #Supress Errors
    $ErrorActionPreference = 'SilentlyContinue'

    #Runs to find all files that match the query on all included computers and outputs the results to a CSV
    Get-Content $computers |
    ForEach-Object { Get-ChildItem "\\$_\$path" -Include $include -Recurse } |
    Select-Object Name, Directory, Length, LastAccessTime, LastWriteTime, CreationTime |
    Export-Csv $csvout -Append -NoTypeInformation

    #Restores default error action of show
    $ErrorActionPreference = 'Continue'
}

function Get-ADInfo {

    <#
    .Synopsis
    -Taylor Lee
    Modified 05172019
 
    .Description
    This function will return domain info. Requires the Active Directory Module.
 
    .NOTES
    Requires the Active Directory Module
 
    .Link
    Get-PCInfo
    #>


    [CmdletBinding()]
    param (
    )

    Import-Module ActiveDirectory

    Get-ADDomain |
    Select-Object Name, Forest, ChildDomains, DistinguishedName, DNSRoot, DomainMode, ReplicaDirectoryServers, InfrastructureMaster, RIDMaster, PDCEmulator |
    Format-List

    Get-ADForest |
    Select-Object DomainNamingMaster, SchemaMaster |
    Format-List

}

function Get-Applications {
    <#
.SYNOPSIS
Sourced from https://mcpmag.com/articles/2017/07/27/gathering-installed-software-using-powershell.aspx
Created by Boe Prox
 
.DESCRIPTION
Get's detailed information on installed applications and their uninstall strings.
 
.EXAMPLE
Get installed software outputted to a table
 
Get-Software | ft
 
.EXAMPLE
Get installed software on all online domain joined Endpoints
 
$Computername = get-adcomputer -filter *
$computername = Get-Software
 
.EXAMPLE
Get installed software on all computers listed in a text file
 
$Computername = get-content c:\computers.txt
$computername = Get-Software
 
.Link
Uninstall-Application
#>


    [OutputType('System.Software.Inventory')]
    [Cmdletbinding()]
    Param(
        [Parameter(ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True)]
        [String[]]
        $Computername = $env:COMPUTERNAME
    )

    Begin {
    }

    Process {
        ForEach ($Computer in  $Computername) {
            If (Test-Connection -ComputerName  $Computer -Count  1 -Quiet) {
                $Paths = @("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall", "SOFTWARE\\Wow6432node\\Microsoft\\Windows\\CurrentVersion\\Uninstall")
                ForEach ($Path in $Paths) {
                    Write-Verbose  "Checking Path: $Path"

                    # Create an instance of the Registry Object and open the HKLM base key
                    Try {
                        $reg = [microsoft.win32.registrykey]::OpenRemoteBaseKey('LocalMachine', $Computer, 'Registry64')
                    }
                    Catch {
                        Write-Error $_
                        Continue
                    }

                    # Drill down into the Uninstall key using the OpenSubKey Method
                    Try {
                        $regkey = $reg.OpenSubKey($Path)

                        # Retrieve an array of string that contain all the subkey names
                        $subkeys = $regkey.GetSubKeyNames()

                        # Open each Subkey and use GetValue Method to return the required values for each
                        ForEach ($key in $subkeys) {
                            Write-Verbose "Key: $Key"
                            $thisKey = $Path + "\\" + $key
                            Try {
                                $thisSubKey = $reg.OpenSubKey($thisKey)

                                # Prevent Objects with empty DisplayName
                                $DisplayName = $thisSubKey.getValue("DisplayName")
                                If ($DisplayName -AND $DisplayName -notmatch '^Update for|rollup|^Security Update|^Service Pack|^HotFix') {
                                    $Date = $thisSubKey.GetValue('InstallDate')
                                    If ($Date) {
                                        Try {
                                            $Date = [datetime]::ParseExact($Date, 'yyyyMMdd', $Null)
                                        }
                                        Catch {
                                            Write-Warning "$($Computer): $_ <$($Date)>"
                                            $Date = $Null
                                        }
                                    }

                                    # Create New Object with empty Properties
                                    $Publisher = Try {
                                        $thisSubKey.GetValue('Publisher').Trim()
                                    }
                                    Catch {
                                        $thisSubKey.GetValue('Publisher')
                                    }
                                    $Version = Try {

                                        #Some weirdness with trailing [char]0 on some strings
                                        $thisSubKey.GetValue('DisplayVersion').TrimEnd(([char[]](32, 0)))
                                    }
                                    Catch {
                                        $thisSubKey.GetValue('DisplayVersion')
                                    }

                                    $UninstallString = Try {
                                        $thisSubKey.GetValue('UninstallString').Trim()
                                    }
                                    Catch {
                                        $thisSubKey.GetValue('UninstallString')
                                    }

                                    $InstallLocation = Try {
                                        $thisSubKey.GetValue('InstallLocation').Trim()
                                    }
                                    Catch {
                                        $thisSubKey.GetValue('InstallLocation')
                                    }

                                    $InstallSource = Try {
                                        $thisSubKey.GetValue('InstallSource').Trim()
                                    }
                                    Catch {
                                        $thisSubKey.GetValue('InstallSource')
                                    }

                                    $HelpLink = Try {
                                        $thisSubKey.GetValue('HelpLink').Trim()
                                    }
                                    Catch {
                                        $thisSubKey.GetValue('HelpLink')
                                    }

                                    $Object = [pscustomobject]@{
                                        Computername    = $Computer
                                        DisplayName     = $DisplayName
                                        Version         = $Version
                                        InstallDate     = $Date
                                        Publisher       = $Publisher
                                        UninstallString = $UninstallString
                                        InstallLocation = $InstallLocation
                                        InstallSource   = $InstallSource
                                        HelpLink        = $thisSubKey.GetValue('HelpLink')
                                        EstimatedSizeMB = [decimal]([math]::Round(($thisSubKey.GetValue('EstimatedSize') * 1024) / 1MB, 2))
                                    }

                                    $Object.pstypenames.insert(0, 'System.Software.Inventory')
                                    Write-Output $Object
                                }
                            }
                            Catch {
                                Write-Warning "$Key : $_"
                            }
                        }
                    }
                    Catch { }

                    $reg.Close()
                }
            }
            Else {
                Write-Error  "$($Computer): unable to reach remote system!"
            }
        }
    }
}

function Get-AuthPolicy {
    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 071219
 
    .DESCRIPTION
    Used to view existing Authentication Polocies for Exchange Online Mailboxes
 
    Use of Modern Authentication Only is important for securing against Password Spray Attacks. New attacks on Basic authentication allow for taking control of an Exchange Online account by simply sending a malicious link to a target.
 
    .EXAMPLE
    Gets the Authentication Policy out to a grid view
 
    Get-AuthPolicy | Out-GridView
 
    .NOTES
    Requires the Exchange Online module be installed, imported, and Connected.
 
    .LINK
    New-AuthPolicy
    Set-AuthPolicy
    #>

    [CmdletBinding()]
    Param (
    )

    Get-Recipient -RecipientTypeDetails UserMailbox -ResultSize Unlimited | Get-User | Select-Object DisplayName, AuthenticationPolicy, Sts*
}

function Get-CloseEncounters {
    [console]::beep(900, 400);
    [console]::beep(1000, 400);
    [console]::beep(800, 400);
    [console]::beep(400, 400);
    [console]::beep(600, 1600);
    [console]::beep(900, 350);
    [console]::beep(1000, 350);
    [console]::beep(800, 350);
    [console]::beep(400, 350);
    [console]::beep(600, 1400);
    [console]::beep(900, 300);
    [console]::beep(1000, 300);
    [console]::beep(800, 300);
    [console]::beep(400, 300);
    [console]::beep(600, 1200);
    [System.Threading.Thread]::Sleep(400);
    [console]::beep(900, 400);
    [console]::beep(1000, 400);
    [console]::beep(800, 400);
    [console]::beep(400, 400);
    [console]::beep(600, 1600);
}

function Get-DCLockoutEvents2 {

    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 05172019
 
    .DESCRIPTION
    Parse Logs 4740 and 4776 on the PDCEmulator for workstations causing a lockout. Null lockout location events are filtered. Best if run shortly after a lockout.
 
    .EXAMPLE
    Get-DCLockoutEvents2 -identity Joe
 
    .Notes
    Requires The Active Directory Module
 
    .Link
    Get-LockedAccounts
    Get-PasswordExpired
    Unlock-Account
    Unlock-AllAccounts
    #>


    [CmdletBinding(SupportsShouldProcess)]
    Param(
        [Parameter(Mandatory = $True)]
        [String]$Identity
    )

    #Getting the PDCEmulator
    $DomainControllers = Get-ADDomainController -Filter *
    $PDCEmulator = ($DomainControllers | Where-Object { $_.OperationMasterRoles -contains "PDCEmulator" })

    #Parsing Event Log 4740
    Write-Host "Querying event id 4740 on $PDCEmulator." -Backgroundcolor Black -ForegroundColor Yellow
    $PDCEmulator | ForEach-Object {
        Get-WinEvent -ComputerName $_ -FilterHashtable @{LogName = 'Security'; Id = 4740 } |
        Where-Object { ($_.Properties[1].Value -notlike $null -and $_.Properties[0].Value -eq $Identity) } |
        Select-Object -Property @(
            @{Label = 'User'; Expression = { $_.Properties[0].Value } }
            @{Label = 'LockedOutLocation'; Expression = { $_.Properties[1].Value } }
            @{Label = 'LockedOutTimeStamp'; Expression = { $_.TimeCreated } }
            @{Label = 'DomainController'; Expression = { $_.MachineName } }
            @{Label = 'EventId'; Expression = { $_.Id } }
        ) |
        Format-Table
    }#endforeach

    #Parsing Event Log 4776
    Write-Host "Querying event id 4776 on $PDCEmulator; this will take awhile. Use ctrl+c to end at any time." -Backgroundcolor Black -ForegroundColor Yellow
    $PDCEmulator | ForEach-Object {
        Get-WinEvent -ComputerName $_ -FilterHashtable @{LogName = 'Security'; Id = 4776 } |
        Where-Object { ($_.Properties[2].Value -notlike $null -and $_.Properties[1].Value -eq $Identity -and $_.KeywordsDisplayNames -contains "Audit Failure") } |
        Select-Object -Property @(
            @{Label = 'User'; Expression = { $_.Properties[1].Value } }
            @{Label = 'BadPasswordLocation'; Expression = { $_.Properties[2].Value } }
            @{Label = 'BadPasswordAttemptTime'; Expression = { $_.TimeCreated } }
            @{Label = 'DomainController'; Expression = { $_.MachineName } }
            @{Label = 'EventID'; Expression = { $_.ID } }
        ) |
        Format-Table
    }#endforeach
}#endfunction

function Get-EndpointReport {

    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 05172019
 
    .DESCRIPTION
    Create a CSV report of Active Directory Endpoints
 
    .NOTES
    Requires the Active Directory Module
 
    .Example
    Be sure to specify a filename and extension for the report.
 
    Get-EndpointReport -path C:\UserReport.csv
 
    .Link
    Get-UserReport
    #>


    [CmdletBinding(SupportsShouldProcess)]

    Param (
        [Parameter(Mandatory = $true)]$Path
    )

    Import-Module ActiveDirectory

    Get-ADComputer -Filter { (Enabled -eq $true) } -properties * |
    Select-Object name, OperatingSystem, whenCreated, LastLogonDate |
    Export-Csv $Path -NoTypeInformation

}

function Get-Excuse {

    <#
    .Synopsis
    -Taylor Lee
    Modified 05172019
 
    .DESCRIPTION
    Are you out of excuses. Let powershell help you
    #>


    [CmdletBinding(SupportsShouldProcess)]

    $ex = (Invoke-WebRequest http://pages.cs.wisc.edu/~ballard/bofh/excuses -OutVariable excuses).content.split([Environment]::NewLine)[(Get-Random $excuses.content.split([Environment]::NewLine).count)]

    Write-Host " "
    Write-Host "$ex" -Foregroundcolor Green
    Write-Host " "

    Add-Type -AssemblyName System.Speech
    $SpeechSynth = New-Object System.Speech.Synthesis.SpeechSynthesizer
    $SpeechSynth.Speak("$ex")
}

function Get-FileOwner {

    <#
    .Synopsis
    -Taylor Lee
    Modified 05172019
 
    .Description
    This function produces a CSV listing file owners within a given path
 
    .Example
    Specify the parent folder from which all subfolders are queried and where the report should be saved.
 
     Get-FileOwner -Path c:\users -Report c:\FileOwners.csv
    #>


    [CmdletBinding(SupportsShouldProcess)]

    PARAM (
        [Parameter(Mandatory = $true)]$Path,
        [Parameter(Mandatory = $true)]$Report
    )

    #Check For Admin Privleges
    Get-Elevation

    $LastWrite = @{
        Name       = 'Last Write Time'
        Expression = { $_.LastWriteTime.ToString('u') }
    }
    $Owner = @{
        Name       = 'File Owner'
        Expression = { (Get-Acl $_.FullName).Owner }
    }
    $HostName = @{
        Name       = 'Host Name'
        Expression = { $env:COMPUTERNAME }
    }


    Get-ChildItem -Recurse -Path $Path |
    Select-Object $HostName, $Owner, Name, Directory, $LastWrite, Length |
    Export-Csv -NoTypeInformation $Report

}

function Get-Help2 {
    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 06282019
    -Adapted from JacFearsome's github
    https://github.com/JacFearsome/powershell-scripts
 
 
    .DESCRIPTION
    Produces a GUI for exploring exploring module commands and viewing help for them.
    #>

    [CmdletBinding()]
    [alias('help2')]
    param (
    )

    $getpath = Get-Module AdminToolbox
    $trimpath = $getpath.path.TrimEnd('\AdminToolbox.ps1')
    ."$trimpath\Support\Get-Help2\Powershell-Cmdlet-Explorer.ps1"
}

function Get-FolderSize {
    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 05172019
 
    .DESCRIPTION
    Quckly Finds the size of a path
 
    .EXAMPLE
    Finds the size of the C:\users folder in MegaBytes
 
    Get-Foldersize -Folder c:\users\ -ByteSize MB
 
    .EXAMPLE
    Finds the size of the C:\users folder in GigaBytes
 
    Get-Foldersize -Folder c:\users\ -ByteSize GB
 
    .EXAMPLE
    Finds the size of the C:\users folder in MegaBytes
 
    Get-Foldersize -Folder c:\users\ -ByteSize TB
    #>


    [CmdletBinding()]
    Param (
        [Parameter(Position = 0, Mandatory = $true)]$Folder,
        [Parameter(Position = 1)]$ByteSize
    )

    if ($ByteSize -eq 'MB') {
        "{0:N2} MB" -f ((Get-ChildItem $Folder -Recurse | Measure-Object -Property Length -Sum -ErrorAction Stop).Sum / 1MB)
    }
    elseif ($ByteSize -eq 'GB') {
        "{0:N2} GB" -f ((Get-ChildItem $Folder -Recurse | Measure-Object -Property Length -Sum -ErrorAction Stop).Sum / 1GB)
    }
    elseif ($ByteSize -eq 'TB') {
        "{0:N2} TB" -f ((Get-ChildItem $Folder -Recurse | Measure-Object -Property Length -Sum -ErrorAction Stop).Sum / 1TB)
    }
    else {
        "{0:N2} MB" -f ((Get-ChildItem $Folder -Recurse | Measure-Object -Property Length -Sum -ErrorAction Stop).Sum / 1MB)
    }
}

function Get-ImperialMarch {
    [console]::beep(440, 500)
    [console]::beep(440, 500)
    [console]::beep(440, 500)
    [console]::beep(349, 350)
    [console]::beep(523, 150)

    [console]::beep(440, 500)
    [console]::beep(349, 350)
    [console]::beep(523, 150)
    [console]::beep(440, 1000)

    [console]::beep(659, 500)
    [console]::beep(659, 500)
    [console]::beep(659, 500)
    [console]::beep(698, 350)
    [console]::beep(523, 150)

    [console]::beep(415, 500)
    [console]::beep(349, 350)
    [console]::beep(523, 150)
    [console]::beep(440, 1000)

    [console]::beep(880, 500)
    [console]::beep(440, 350)
    [console]::beep(440, 150)
    [console]::beep(880, 500)
    [console]::beep(830, 250)
    [console]::beep(784, 250)

    [console]::beep(740, 125)
    [console]::beep(698, 125)
    [console]::beep(740, 250)

    [console]::beep(455, 250)
    [console]::beep(622, 500)
    [console]::beep(587, 250)
    [console]::beep(554, 250)

    [console]::beep(523, 125)
    [console]::beep(466, 125)
    [console]::beep(523, 250)

    [console]::beep(349, 125)
    [console]::beep(415, 500)
    [console]::beep(349, 375)
    [console]::beep(440, 125)

    [console]::beep(523, 500)
    [console]::beep(440, 375)
    [console]::beep(523, 125)
    [console]::beep(659, 1000)

    [console]::beep(880, 500)
    [console]::beep(440, 350)
    [console]::beep(440, 150)
    [console]::beep(880, 500)
    [console]::beep(830, 250)
    [console]::beep(784, 250)

    [console]::beep(740, 125)
    [console]::beep(698, 125)
    [console]::beep(740, 250)

    [console]::beep(455, 250)
    [console]::beep(622, 500)
    [console]::beep(587, 250)
    [console]::beep(554, 250)

    [console]::beep(523, 125)
    [console]::beep(466, 125)
    [console]::beep(523, 250)

    [console]::beep(349, 250)
    [console]::beep(415, 500)
    [console]::beep(349, 375)
    [console]::beep(523, 125)

    [console]::beep(440, 500)
    [console]::beep(349, 375)
    [console]::beep(261, 125)
    [console]::beep(440, 1000)
}

function Get-Info {

    <#
    .Synopsis
    -Taylor Lee
    Modified 05302019
 
    .Description
    A functions list for the Powershell Profile
    #>

    [CmdletBinding()]
    [Alias("Get-AdminToolbox")]
    param (
    )

    Write-Host " -------------------------------------------------------------------"                      -Foregroundcolor Green
    Write-Host " | "                                                                                       -Foregroundcolor Green -NoNewline
    Write-Host "Some functions "                                                                           -Foregroundcolor Yellow  -NoNewline
    Write-Host "require additional Powershell Modules "                                         -ForegroundColor Yellow -NoNewline
    Write-Host "|"                                                                                         -Foregroundcolor Green
    Write-Host " | "                                                                                       -Foregroundcolor Green -NoNewline
    Write-Host "Use "                                                                                      -Foregroundcolor Yellow -NoNewline
    Write-Host "Get-Help <Command> -full "                                                                 -ForegroundColor Cyan -NoNewline
    Write-Host "to view any prerequisites "                                                       -Foregroundcolor Yellow -NoNewline
    Write-Host "|"                                                                                         -Foregroundcolor Green
    Write-Host " | "                                                                                       -Foregroundcolor Green -NoNewline
    Write-Host "Use "                                                                                      -ForegroundColor Yellow -NoNewline
    Write-Host "Get-Help2 "                                                                                -ForegroundColor Cyan -NoNewline
    Write-Host "for a Graphical cmdlet explorer "                                        -ForegroundColor Yellow -NoNewline
    Write-Host "|"                                                                                         -Foregroundcolor Green
    Write-Host " -------------------------------------------------------------------"                      -Foregroundcolor Green
    Pause
    Write-Host "Active Directoy Commands"                                                                  -Foregroundcolor green
    Write-Host "Get-ADInfo ..Gets info on local domain"                                    -Foregroundcolor cyan
    Write-Host "Get-DCLockoutEvents2 ..Gets endpoints causing user lockouts"                         -ForegroundColor cyan
    Write-Host "Get-EndpointReport ..Gets a Report of AD Endpoints"                                -Foregroundcolor cyan
    Write-Host "Get-LockedAccounts ..Gets locked AD accounts"                                      -Foregroundcolor cyan
    Write-Host "Get-PasswordExpired ..Gets AD accounts with Expired Passwords"                      -Foregroundcolor cyan
    Write-Host "Get-UserReport ..Gets a Report of AD Users"                                    -Foregroundcolor cyan
    Write-Host "Set-Password ..Sets an AD Password"                                          -Foregroundcolor cyan
    Write-Host "Unlock-Account ..Unlocks an AD account"                                        -Foregroundcolor cyan
    Write-Host "Unlock-AllAccounts ..Unlocks all AD accounts"                                      -Foregroundcolor cyan
    Write-Host " "
    Write-Host "Custom Modules"                                                                            -Foregroundcolor green
    Write-Host "AdminToolbox ..Module with many useful tools"                                -ForegroundColor cyan
    Write-Host "FFTools ..Module for FFMpeg"                                            -Foregroundcolor cyan
    Write-Host "PCSetup ..Module for PC Setup"                                          -Foregroundcolor cyan
    Write-Host "VmwareAutomate ..Module for Automating VMware Tasks"                            -Foregroundcolor cyan
    Write-Host " "
    Write-Host "Endpoint Management Commands"                                                              -Foregroundcolor green
    Write-Host "Add-LocalAdmin ..Adds a local admin to the endpoint"                           -Foregroundcolor cyan
    Write-Host "Disable-ShakeToMinimize ..Disables Annoying Shake to Minimize"                          -Foregroundcolor cyan
    Write-Host "Disable-Standby ..Disables Hibernate and Sleep"                                 -Foregroundcolor cyan
    Write-Host "Get-Applications ..Gets a list of installed Applications"                        -Foregroundcolor cyan
    Write-Host "Get-Management ..Gets Computer Management for another endpoint"                -Foregroundcolor cyan
    Write-Host "Get-PCInfo ..Gets info on targeted PC"                                     -Foregroundcolor cyan
    Write-Host "Reset-NetworkStack ..Reset TCP/IP and Winsock"                                     -Foregroundcolor cyan
    Write-Host "Reset-NetworkAdapter ..Reset Network Adapters"                                       -Foregroundcolor cyan
    Write-Host "Restart-Endpoint ..Restart the endpoint after X provided hours"                  -Foregroundcolor cyan
    Write-Host "Set-UAC ..Sets the UAC state"                                           -Foregroundcolor cyan
    Write-Host "Uninstall-Applications ..Uninstalls a selected Application"                            -Foregroundcolor cyan
    Write-Host " "
    Write-Host "Exchange Commands"                                                                         -Foregroundcolor green
    Write-Host "Add-DistributionMember ..Adds a mailbox to a Distibution Group"                        -Foregroundcolor cyan
    Write-Host "Get-MailLog ..Gets a csv of mail logs"                                      -Foregroundcolor cyan
    Write-Host "Get-UserDisabledMailboxes ..Gets mailboxes associated with disabled ad accounts"          -Foregroundcolor cyan
    Write-Host "Get-VirtualDirectories ..Gets IIS virtual directories for Exchange"                    -ForegroundColor cyan
    Write-Host "Set-VirtualDirectories ..Sets IIS virtual directories for Exchange"                    -ForegroundColor cyan
    Write-Host " "
    Write-Host "File Commands"                                                                             -Foregroundcolor green
    Write-Host "Get-FileOwner ..Gets CSV of file owners for a path"                           -Foregroundcolor cyan
    Write-Host "Get-FolderSize ..Gets FolderSize of a single folder quickly"                   -Foregroundcolor cyan
    Write-Host "Find-ComputersFiles ..Finds queried files across 1 or more Computers"               -ForegroundColor cyan
    Write-Host "Remove-All ..Removes many files quickly to free up space"                  -Foregroundcolor cyan
    Write-Host "Remove-DisabledADProfiles ..Removes local profiles of disabled AD users"                  -Foregroundcolor cyan
    Write-Host "Remove-OlderThan ..Removes folders and files older than"                         -Foregroundcolor cyan
    Write-Host "Remove-Path ..Removes specified files and folders"                          -Foregroundcolor cyan
    Write-Host " "
    Write-Host "Fun"                                                                                       -Foregroundcolor green
    Write-Host "Get-CloseEncounters ..Get Close Encounters"                                         -Foregroundcolor cyan
    Write-Host "Get-Excuse ..Gets a joke"                                                  -Foregroundcolor cyan
    Write-Host "Get-ImperialMarch ..Get Imperial March"                                           -Foregroundcolor cyan
    Write-Host "Get-MissionImpossible ..Get Mission Impossible"                                       -Foregroundcolor cyan
    Write-Host "Get-Mario ..Get Mario"                                                    -Foregroundcolor cyan
    Write-Host "Get-Tetris ..Get Tetris"                                                   -Foregroundcolor cyan
    Write-Host "Get-Weather ..Get The Weather"                                              -Foregroundcolor cyan
    Write-Host " "
    Write-Host "Networking Commands"                                                                       -Foregroundcolor green
    Write-Host "Clear-Arp ..Clears the local arp table"                                   -Foregroundcolor cyan
    Write-Host "Clear-DNSClientCache ..Clears the DNS Cache"                                         -Foregroundcolor cyan
    Write-Host "Get-DNSClientCache ..Gets the DNS Cache"                                           -Foregroundcolor cyan
    Write-Host "Get-NetIPConfiguration ..Gets Network Interface Config"                                -Foregroundcolor cyan
    Write-Host "Get-NetworkStatistics ..Gets active connections and associated processes"             -Foregroundcolor cyan
    Write-Host "Get-PublicIP ..Gets Public Whois Info for specified address"                 -ForegroundColor cyan
    Write-Host "Invoke-PSNmap ..Invoke nmap scan on targets"                                  -ForegroundColor cyan
    Write-Host "Invoke-PSipcalc ..Invoke CIDR IP Calculator"                                    -ForegroundColor cyan
    Write-Host "Resolve-DNSName ..Resolves DNS and filter for record type"                      -Foregroundcolor cyan
    Write-Host "Start-Iperf ..Starts an Iperf client or host bandwidth test"                -Foregroundcolor cyan
    Write-Host "Test-Netconnection ..Tests Ping, Traceroute, Route Diagnosing, and Port Testing"   -Foregroundcolor cyan
    Write-Host " "
    Write-Host "Office 365 Commands"                                                                       -Foregroundcolor green
    Write-Host "Connect-Office365 ..Connects to Office 365 Module"                                -Foregroundcolor cyan
    Write-Host "Get-AuthPolicy ..Gets Exchange Online Auth Policy"                             -Foregroundcolor cyan
    Write-Host "New-AuthPolicy ..New Exchange Online Auth Policies Created"                    -Foregroundcolor cyan
    Write-Host "Set-AuthPolicy ..Sets Exchange Online Auth Policy"                             -Foregroundcolor cyan
    Write-Host "Start-AzureSync ..Starts an Azure AD and Local AD Sync"                         -Foregroundcolor cyan
    Write-Host " "
    Write-Host "Print/er Management Commands"                                                              -Foregroundcolor green
    Write-Host "Get-Printers ..Gets printer information"                                     -Foregroundcolor cyan
    Write-Host "Get-PrintManagement ..Gets Print Management"                                        -Foregroundcolor cyan
    Write-Host "Remove-PrintQueue ..Removes all print queues"                                     -Foregroundcolor cyan
    Write-Host " "
    Write-Host "Remoting"                                                                                  -Foregroundcolor green
    Write-Host "Connect-SSH ..Connects to SSH Server"                                       -Foregroundcolor cyan
    Write-Host "Enable-PSRemoting ..Enables PSRemoting on local endpoint"                         -Foregroundcolor cyan
    Write-Host "Enable-Remoting ..Enables PSRemoting on remote endpoint"                        -Foregroundcolor cyan
    Write-Host "Install-SSH ..Installs OpenSSH Features"                                    -Foregroundcolor cyan
    Write-Host "Invoke-ServiceRecovery ..Invokes a Service Restart on all Endpoints"                   -Foregroundcolor cyan
}

function get-intro {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $false)]
        [ValidateSet('yes', 'no')]
        $clear = "yes"
    )

    if ($clear -eq "no") {
    }

    if ($clear -eq "yes") {
        Clear-Host
    }

    Write-Host "
                    _______ __ __
                   | _ .--| .--------|__.-----.
                   |. 1 | _ | | | |
                   |. _ |_____|__|__|__|__|__|__|
                   |: | | _______ __ __
                   |::.|:. | | .-----.-----| | |--.-----.--.--.
                   '--- ---' |.| | | _ | _ | | _ | _ |_ _|
                                  '-|. |-|_____|_____|__|_____|_____|__.__|
                                    |: |
                                    |::.|
                                    '---'
"
 -Foregroundcolor Green

    Write-Host " --------------------------------------------------------------------"      -Foregroundcolor Green
    Write-Host " > "                                                                        -Foregroundcolor Green   -NoNewline
    Write-Host "Use "                                                                                   -ForegroundColor Yellow  -NoNewline
    Write-Host "Get-Info "                                                                              -ForegroundColor Cyan    -NoNewline
    Write-Host "to see a list of Commands "                                   -ForegroundColor Yellow  -NoNewline
    Write-Host "<"                                                                                      -Foregroundcolor Green
    Write-Host " > "                                                                        -Foregroundcolor Green   -NoNewline
    Write-Host "Use "                                                                                   -ForegroundColor Yellow  -NoNewline
    Write-Host "Get-Intro "                                                                             -ForegroundColor Cyan    -NoNewline
    Write-Host "to Clear-Host and return here "                                    -ForegroundColor Yellow  -NoNewline
    Write-Host "<"                                                                                      -Foregroundcolor Green
    Write-Host " --------------------------------------------------------------------"      -Foregroundcolor Green

    Write-Host " "
}

function Get-LockedAccounts {

    <#
    .Synopsis
    -Taylor Lee
    Modified 05172019
 
    .Description
    Return a list of Locked Active Directory Accounts
 
    .Notes
    Requires the Active Directory Module
 
    .Link
    Get-DCLockoutEvents2
    Get-PasswordExpired
    Set-Password
    Unlock-Account
    Unlock-AllAccounts
    #>


    Import-Module ActiveDirectory

    Search-ADAccount -Lockedout |
    Select-Object Name, SamAccountName, UserPrincipalName |
    Sort-Object Name |
    Format-Table -AutoSize
}

function Get-MailLog {

    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 05172019
 
    .DESCRIPTION
    Creates a csv file containg logs of mail in a given time frame.
 
    .NOTES
    Requires the Microsoft Exchange module.
 
    .EXAMPLE
    Specify the date range, report path, and amount of records to return.
 
    Get-MailLog -Start 05/14/2017 -End 05/14/2018 -ExportPath C:\MailLog.CSV -Resultsize 10000
 
    .Link
    Get-MessageTrackingLog
    #>


    [CmdletBinding(SupportsShouldProcess)]

    Param (
        [Parameter(Mandatory = $true)]$Start,
        [Parameter(Mandatory = $true)]$End,
        [Parameter(Mandatory = $true)]$ExportPath,
        [Parameter(Mandatory = $true)]$ResultSize
    )

    Get-MessageTrackingLog -Start "$Start" -End "$End" -ResultSize $ResultSize |
    Select-Object Timestamp, Sender, { $_.Recipients }, { $_.Recipientstatus }, EventID, Source, Directionality, MessageSubject, TotalBytes, SourceContext, ServerIP, ClientHostName, ConnectorID, MessageId, OriginalClientIP, { $_.EventData } |
    Export-Csv -path $ExportPath -NoTypeInformation
}

function Get-Management {

    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 05172019
 
    .DESCRIPTION
    Opens Computer management connected for another PC
 
    .Example
    Specify the computer you are connecting to.
 
    Get-Management -computer PCName
    #>


    [CmdletBinding()]

    Param (
        [Parameter(Mandatory = $true)]$computer
    )

    compmgmt.msc /computer:$computer

}

function Get-Mario {
    [System.Console]::Beep(659, 125);
    [System.Console]::Beep(659, 125);
    [System.Threading.Thread]::Sleep(125);
    [System.Console]::Beep(659, 125);
    [System.Threading.Thread]::Sleep(167);
    [System.Console]::Beep(523, 125);
    [System.Console]::Beep(659, 125);
    [System.Threading.Thread]::Sleep(125);
    [System.Console]::Beep(784, 125);
    [System.Threading.Thread]::Sleep(375);
    [System.Console]::Beep(392, 125);
    [System.Threading.Thread]::Sleep(375);
    [System.Console]::Beep(523, 125);
    [System.Threading.Thread]::Sleep(250);
    [System.Console]::Beep(392, 125);
    [System.Threading.Thread]::Sleep(250);
    [System.Console]::Beep(330, 125);
    [System.Threading.Thread]::Sleep(250);
    [System.Console]::Beep(440, 125);
    [System.Threading.Thread]::Sleep(125);
    [System.Console]::Beep(494, 125);
    [System.Threading.Thread]::Sleep(125);
    [System.Console]::Beep(466, 125);
    [System.Threading.Thread]::Sleep(42);
    [System.Console]::Beep(440, 125);
    [System.Threading.Thread]::Sleep(125);
    [System.Console]::Beep(392, 125);
    [System.Threading.Thread]::Sleep(125);
    [System.Console]::Beep(659, 125);
    [System.Threading.Thread]::Sleep(125);
    [System.Console]::Beep(784, 125);
    [System.Threading.Thread]::Sleep(125);
    [System.Console]::Beep(880, 125);
    [System.Threading.Thread]::Sleep(125);
    [System.Console]::Beep(698, 125);
    [System.Console]::Beep(784, 125);
    [System.Threading.Thread]::Sleep(125);
    [System.Console]::Beep(659, 125);
    [System.Threading.Thread]::Sleep(125);
    [System.Console]::Beep(523, 125);
    [System.Threading.Thread]::Sleep(125);
    [System.Console]::Beep(587, 125);
    [System.Console]::Beep(494, 125);
    [System.Threading.Thread]::Sleep(125);
    [System.Console]::Beep(523, 125);
}

function Get-MissionImpossible {
    [console]::beep(784, 150)
    Start-Sleep -m 300
    [console]::beep(784, 150)
    Start-Sleep -m 300
    [console]::beep(932, 150)
    Start-Sleep -m 150
    [console]::beep(1047, 150)
    Start-Sleep -m 150
    [console]::beep(784, 150)
    Start-Sleep -m 300
    [console]::beep(784, 150)
    Start-Sleep -m 300
    [console]::beep(699, 150)
    Start-Sleep -m 150
    [console]::beep(740, 150)
    Start-Sleep -m 150
    [console]::beep(784, 150)
    Start-Sleep -m 300
    [console]::beep(784, 150)
    Start-Sleep -m 300
    [console]::beep(932, 150)
    Start-Sleep -m 150
    [console]::beep(1047, 150)
    Start-Sleep -m 150
    [console]::beep(784, 150)
    Start-Sleep -m 300
    [console]::beep(784, 150)
    Start-Sleep -m 300
    [console]::beep(699, 150)
    Start-Sleep -m 150
    [console]::beep(740, 150)
    Start-Sleep -m 150
    [console]::beep(932, 150)
    [console]::beep(784, 150)
    [console]::beep(587, 1200)
    Start-Sleep -m 75
    [console]::beep(932, 150)
    [console]::beep(784, 150)
    [console]::beep(554, 1200)
    Start-Sleep -m 75
    [console]::beep(932, 150)
    [console]::beep(784, 150)
    [console]::beep(523, 1200)
    Start-Sleep -m 150
    [console]::beep(466, 150)
    [console]::beep(523, 150)
}

function Get-NetworkStatistics {
    <#
    .SYNOPSIS
        Display current TCP/IP connections for local or remote system
 
    .functionALITY
        Computers
 
    .DESCRIPTION
        Display current TCP/IP connections for local or remote system. Includes the process ID (PID) and process name for each connection.
        If the port is not yet established, the port number is shown as an asterisk (*).
 
    .PARAMETER ProcessName
        Gets connections by the name of the process. The default value is '*'.
 
    .PARAMETER Port
        The port number of the local computer or remote computer. The default value is '*'.
 
    .PARAMETER Address
        Gets connections by the IP address of the connection, local or remote. Wildcard is supported. The default value is '*'.
 
    .PARAMETER Protocol
        The name of the protocol (TCP or UDP). The default value is '*' (all)
 
    .PARAMETER State
        Indicates the state of a TCP connection. The possible states are as follows:
 
        Closed - The TCP connection is closed.
        Close_Wait - The local endpoint of the TCP connection is waiting for a connection termination request from the local user.
        Closing - The local endpoint of the TCP connection is waiting for an acknowledgement of the connection termination request sent previously.
        Delete_Tcb - The transmission control buffer (TCB) for the TCP connection is being deleted.
        Established - The TCP handshake is complete. The connection has been established and data can be sent.
        Fin_Wait_1 - The local endpoint of the TCP connection is waiting for a connection termination request from the remote endpoint or for an acknowledgement of the connection termination request sent previously.
        Fin_Wait_2 - The local endpoint of the TCP connection is waiting for a connection termination request from the remote endpoint.
        Last_Ack - The local endpoint of the TCP connection is waiting for the final acknowledgement of the connection termination request sent previously.
        Listen - The local endpoint of the TCP connection is listening for a connection request from any remote endpoint.
        Syn_Received - The local endpoint of the TCP connection has sent and received a connection request and is waiting for an acknowledgment.
        Syn_Sent - The local endpoint of the TCP connection has sent the remote endpoint a segment header with the synchronize (SYN) control bit set and is waiting for a matching connection request.
        Time_Wait - The local endpoint of the TCP connection is waiting for enough time to pass to ensure that the remote endpoint received the acknowledgement of its connection termination request.
        Unknown - The TCP connection state is unknown.
 
        Values are based on the TcpState Enumeration:
        http://msdn.microsoft.com/en-us/library/system.net.networkinformation.tcpstate%28VS.85%29.aspx
 
        Cookie Monster - modified these to match netstat output per here:
        http://support.microsoft.com/kb/137984
 
    .PARAMETER ComputerName
        If defined, run this command on a remote system via WMI. \\computername\c$\netstat.txt is created on that system and the results returned here
 
    .PARAMETER ShowHostNames
        If specified, will attempt to resolve local and remote addresses.
 
    .PARAMETER tempFile
        Temporary file to store results on remote system. Must be relative to remote system (not a file share). Default is "C:\netstat.txt"
 
    .PARAMETER AddressFamily
        Filter by IP Address family: IPv4, IPv6, or the default, * (both).
 
        If specified, we display any result where both the localaddress and the remoteaddress is in the address family.
 
    .EXAMPLE
        Get-NetworkStatistics | Format-Table
 
    .EXAMPLE
        Get-NetworkStatistics iexplore -computername k-it-thin-02 -ShowHostNames | Format-Table
 
    .EXAMPLE
        Get-NetworkStatistics -ProcessName md* -Protocol tcp
 
    .EXAMPLE
        Get-NetworkStatistics -Address 192* -State LISTENING
 
    .EXAMPLE
        Get-NetworkStatistics -State LISTENING -Protocol tcp
 
    .EXAMPLE
        Get-NetworkStatistics -Computername Computer1, Computer2
 
    .EXAMPLE
        'Computer1', 'Computer2' | Get-NetworkStatistics
 
    .EXAMPLE
        Get-NetworkStatistics | where {$_.LocalAddress -like "192.168.240.8"} | sort processname | ft
 
    .OUTPUTS
        System.Management.Automation.PSObject
 
    .NOTES
        Author: Shay Levy, code butchered by Cookie Monster
        Shay's Blog: http://PowerShay.com
        Cookie Monster's Blog: http://ramblingcookiemonster.github.io/
 
    .LINK
        Clear-Arp
        Clear-DNSClientCache
        Get-DNSClientCache
        Get-NetIPConfiguration
        Get-PublicIP
        Resolve-DNSName
        Test-Netconnection
    #>


    [OutputType('System.Management.Automation.PSObject')]
    [CmdletBinding()]
    param(

        [Parameter(Position = 0)]
        [System.String]$ProcessName = '*',

        [Parameter(Position = 1)]
        [System.String]$Address = '*',

        [Parameter(Position = 2)]
        $Port = '*',

        [Parameter(Position = 3,
            ValueFromPipeline = $True,
            ValueFromPipelineByPropertyName = $True)]
        [System.String[]]$ComputerName = $env:COMPUTERNAME,

        [ValidateSet('*', 'tcp', 'udp')]
        [System.String]$Protocol = '*',

        [ValidateSet('*', 'Closed', 'Close_Wait', 'Closing', 'Delete_Tcb', 'DeleteTcb', 'Established', 'Fin_Wait_1', 'Fin_Wait_2', 'Last_Ack', 'Listening', 'Syn_Received', 'Syn_Sent', 'Time_Wait', 'Unknown')]
        [System.String]$State = '*',

        [switch]$ShowHostnames,

        [switch]$ShowProcessNames = $true,

        [System.String]$TempFile = "C:\netstat.txt",

        [validateset('*', 'IPv4', 'IPv6')]
        [string]$AddressFamily = '*'
    )

    begin {
        #Define properties
        $properties = 'ComputerName', 'Protocol', 'LocalAddress', 'LocalPort', 'RemoteAddress', 'RemotePort', 'State', 'ProcessName', 'PID'

        #store hostnames in array for quick lookup
        $dnsCache = @{ }

    }

    process {

        foreach ($Computer in $ComputerName) {

            #Collect processes
            if ($ShowProcessNames) {
                Try {
                    $processes = Get-Process -ComputerName $Computer -ErrorAction stop | Select-Object name, id
                }
                Catch {
                    Write-Warning "Could not run Get-Process -computername $Computer. Verify permissions and connectivity. Defaulting to no ShowProcessNames"
                    $ShowProcessNames = $false
                }
            }

            #Handle remote systems
            if ($Computer -ne $env:COMPUTERNAME) {

                #define command
                [string]$cmd = "cmd /c c:\windows\system32\netstat.exe -ano >> $tempFile"

                #define remote file path - computername, drive, folder path
                $remoteTempFile = "\\{0}\{1}`${2}" -f "$Computer", (Split-Path $tempFile -qualifier).TrimEnd(":"), (Split-Path $tempFile -noqualifier)

                #delete previous results
                Try {
                    $null = Invoke-WmiMethod -class Win32_process -name Create -ArgumentList "cmd /c del $tempFile" -ComputerName $Computer -ErrorAction stop
                }
                Catch {
                    Write-Warning "Could not invoke create win32_process on $Computer to delete $tempfile"
                }

                #run command
                Try {
                    $processID = (Invoke-WmiMethod -class Win32_process -name Create -ArgumentList $cmd -ComputerName $Computer -ErrorAction stop).processid
                }
                Catch {
                    #If we didn't run netstat, break everything off
                    Throw $_
                    Break
                }

                #wait for process to complete
                while (
                    #This while should return true until the process completes
                    $(
                        try {
                            Get-Process -id $processid -computername $Computer -ErrorAction Stop
                        }
                        catch {
                            $FALSE
                        }
                    )
                ) {
                    Start-Sleep -seconds 2
                }

                #gather results
                if (Test-Path $remoteTempFile) {

                    Try {
                        $results = Get-Content $remoteTempFile | Select-String -Pattern '\s+(TCP|UDP)'
                    }
                    Catch {
                        Throw "Could not get content from $remoteTempFile for results"
                        Break
                    }

                    Remove-Item $remoteTempFile -force

                }
                else {
                    Throw "'$tempFile' on $Computer converted to '$remoteTempFile'. This path is not accessible from your system."
                    Break
                }
            }
            else {
                #gather results on local PC
                $results = NETSTAT.EXE -ano | Select-String -Pattern '\s+(TCP|UDP)'
            }

            #initialize counter for progress
            $totalCount = $results.count
            $count = 0

            #Loop through each line of results
            foreach ($result in $results) {

                $item = $result.line.split(' ', [System.StringSplitOptions]::RemoveEmptyEntries)

                if ($item[1] -notmatch '^\[::') {

                    #parse the netstat line for local address and port
                    if (($la = $item[1] -as [ipaddress]).AddressFamily -eq 'InterNetworkV6') {
                        $localAddress = $la.IPAddressToString
                        $localPort = $item[1].split('\]:')[-1]
                    }
                    else {
                        $localAddress = $item[1].split(':')[0]
                        $localPort = $item[1].split(':')[-1]
                    }

                    #parse the netstat line for remote address and port
                    if (($ra = $item[2] -as [ipaddress]).AddressFamily -eq 'InterNetworkV6') {
                        $remoteAddress = $ra.IPAddressToString
                        $remotePort = $item[2].split('\]:')[-1]
                    }
                    else {
                        $remoteAddress = $item[2].split(':')[0]
                        $remotePort = $item[2].split(':')[-1]
                    }

                    #Filter IPv4/IPv6 if specified
                    if ($AddressFamily -ne "*") {
                        if ($AddressFamily -eq 'IPv4' -and $localAddress -match ':' -and $remoteAddress -match ':|\*' ) {
                            #Both are IPv6, or ipv6 and listening, skip
                            Write-Verbose "Filtered by AddressFamily:`n$result"
                            continue
                        }
                        elseif ($AddressFamily -eq 'IPv6' -and $localAddress -notmatch ':' -and ( $remoteAddress -notmatch ':' -or $remoteAddress -match '*' ) ) {
                            #Both are IPv4, or ipv4 and listening, skip
                            Write-Verbose "Filtered by AddressFamily:`n$result"
                            continue
                        }
                    }

                    #parse the netstat line for other properties
                    $procId = $item[-1]
                    $proto = $item[0]
                    $status = if ($item[0] -eq 'tcp') { $item[3] } else { $null }

                    #Filter the object
                    if ($remotePort -notlike $Port -and $localPort -notlike $Port) {
                        Write-Verbose "remote $Remoteport local $localport port $port"
                        Write-Verbose "Filtered by Port:`n$result"
                        continue
                    }

                    if ($remoteAddress -notlike $Address -and $localAddress -notlike $Address) {
                        Write-Verbose "Filtered by Address:`n$result"
                        continue
                    }

                    if ($status -notlike $State) {
                        Write-Verbose "Filtered by State:`n$result"
                        continue
                    }

                    if ($proto -notlike $Protocol) {
                        Write-Verbose "Filtered by Protocol:`n$result"
                        continue
                    }

                    #Display progress bar prior to getting process name or host name
                    Write-Progress  -Activity "Resolving host and process names"`
                        -Status "Resolving process ID $procId with remote address $remoteAddress and local address $localAddress"`
                        -PercentComplete (( $count / $totalCount ) * 100)

                    #If we are running showprocessnames, get the matching name
                    if ($ShowProcessNames -or $PSBoundParameters.ContainsKey -eq 'ProcessName') {

                        #handle case where process spun up in the time between running get-process and running netstat
                        if ($procName = $processes | Where-Object { $_.id -eq $procId } | Select-Object -ExpandProperty name ) { }
                        else { $procName = "Unknown" }

                    }
                    else { $procName = "NA" }

                    if ($procName -notlike $ProcessName) {
                        Write-Verbose "Filtered by ProcessName:`n$result"
                        continue
                    }

                    #if the showhostnames switch is specified, try to map IP to hostname
                    if ($showHostnames) {
                        $tmpAddress = $null
                        try {
                            if ($remoteAddress -eq "127.0.0.1" -or $remoteAddress -eq "0.0.0.0") {
                                $remoteAddress = $Computer
                            }
                            elseif ($remoteAddress -match "\w") {

                                #check with dns cache first
                                if ($dnsCache.containskey( $remoteAddress)) {
                                    $remoteAddress = $dnsCache[$remoteAddress]
                                    Write-Verbose "using cached REMOTE '$remoteAddress'"
                                }
                                else {
                                    #if address isn't in the cache, resolve it and add it
                                    $tmpAddress = $remoteAddress
                                    $remoteAddress = [System.Net.DNS]::GetHostByAddress("$remoteAddress").hostname
                                    $dnsCache.add($tmpAddress, $remoteAddress)
                                    Write-Verbose "using non cached REMOTE '$remoteAddress`t$tmpAddress"
                                }
                            }
                        }
                        catch { }

                        try {

                            if ($localAddress -eq "127.0.0.1" -or $localAddress -eq "0.0.0.0") {
                                $localAddress = $Computer
                            }
                            elseif ($localAddress -match "\w") {
                                #check with dns cache first
                                if ($dnsCache.containskey($localAddress)) {
                                    $localAddress = $dnsCache[$localAddress]
                                    Write-Verbose "using cached LOCAL '$localAddress'"
                                }
                                else {
                                    #if address isn't in the cache, resolve it and add it
                                    $tmpAddress = $localAddress
                                    $localAddress = [System.Net.DNS]::GetHostByAddress("$localAddress").hostname
                                    $dnsCache.add($localAddress, $tmpAddress)
                                    Write-Verbose "using non cached LOCAL '$localAddress'`t'$tmpAddress'"
                                }
                            }
                        }
                        catch { }
                    }

                    #Write the object
                    New-Object -TypeName PSObject -Property @{
                        ComputerName  = $Computer
                        PID           = $procId
                        ProcessName   = $procName
                        Protocol      = $proto
                        LocalAddress  = $localAddress
                        LocalPort     = $localPort
                        RemoteAddress = $remoteAddress
                        RemotePort    = $remotePort
                        State         = $status
                    } | Select-Object -Property $properties

                    #Increment the progress counter
                    $count++
                }
            }
        }
    }
}

function Get-PasswordExpired {

    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 05172019
 
    .DESCRIPTION
    Returns a list of Active Directory Accounts with expired passwords
 
    .NOTES
    Requires the Active Directory Module.
 
    .Link
    Get-DCLockoutEvents2
    Get-LockedAccounts
    Set-Password
    Unlock-Account
    Unlock-AllAccounts
    #>


    [CmdletBinding()]
    param (
    )

    Import-Module ActiveDirectory

    Search-ADAccount -PasswordExpired | Select-Object name | Sort-Object name | Format-List

}

function Get-PCInfo {

    <#
    .Synopsis
    -Taylor Lee
    Modified 05172019
 
    .Description
    Returns useful informaion on the local endpoint or another.
    .NOTES
    Requires Powershell 5.1
 
    .EXAMPLE
    Returns PCinfo for the local computer
 
    Get-PCinfo
 
    .EXAMPLE
    Returns PCinfo for a remote computer
 
    Get-PCinfo -computer PCName
 
    .Link
    Get-ADInfo
    #>


    [CmdletBinding()]

    #Prompts for Computer Name
    Param (
        [parameter()]$Computer
    )


    #Variables
    $SystemEnclosure = Get-CimInstance win32_systemenclosure -computername $computer
    $OS = Get-CimInstance Win32_OperatingSystem -Computername $Computer


    #Creating Hash table from variables
    $PCInfo = @{
        Manufacturer   = $SystemEnclosure.Manufacturer
        PCName         = $OS.CSName
        OS             = $OS.Caption
        Architecture   = $OS.OSArchitecture
        AssetTag       = $systemenclosure.serialnumber;
        OSVersion      = $OS.Version
        InstallDate    = $OS.InstallDate
        LastBootUpTime = $OS.LastBootUpTime
    }

    #Writing to Host
    Write-Host " "
    Write-Host "Computer Info" -Foregroundcolor Cyan
    Write-Host "If not run on a Dell machine AssetTag is the Serial Number" -Foregroundcolor Yellow

    #Display Hash Table
    $PCInfo.getenumerator() | Sort-Object -property name | Format-Table -autosize

    #Writing to Host
    Write-Host "Computer Disk Info" -Foregroundcolor Cyan

    #Display Drives
    Get-CimInstance win32_logicaldisk -filter "drivetype=3" -computer $computer |
    Format-Table -Property DeviceID, Volumename, `
    @{Name = "SizeGB"; Expression = { [math]::Round($_.Size / 1GB) } }, `
    @{Name = "FreeGB"; Expression = { [math]::Round($_.Freespace / 1GB, 2) } }, `
    @{Name = "PercentFree"; Expression = { [math]::Round(($_.Freespace / $_.size) * 100, 2) } }

    #Writing to Host
    Write-Host "Network Information" -Foregroundcolor Cyan

    Get-CimInstance win32_networkadapterconfiguration -computer $computer | Where-Object { $_.IPAddress -ne $null } |
    Select-Object IPAddress, DefaultIPGateway, DNSServerSearchOrder, IPSubnet, MACAddress, Caption, DHCPEnabled, DHCPServer, DNSDomainSuffixSearchOrder |
    Format-List

}

function Get-Printers {

    <#
    .Synopsis
    -Taylor Lee
    Modified 06192019
 
    .DESCRIPTION
    This command returns a list of local or remote printers
 
    .EXAMPLE
    Returns printers for the local computer only.
 
    Get-Printers
 
    .EXAMPLE
    -Computer is used to pull printers from remote computers.
 
    Get-Printers -computer PCName
 
    .EXAMPLE
    Return long list of info on the printers
 
    Get-Printers -computer PCName -complex
    #>


    [CmdletBinding()]

    Param (
        [Parameter(Mandatory = $false)]$computer,
        [Parameter(Mandatory = $false)][switch]$complex
    )

    if ($complex) {
        Get-CimInstance cim_printer -computer $computer | Select-Object Name, Drivername, Portname, Status, SystemName, local, shared, CapabilityDescriptions
    }

    else {
        Get-CimInstance cim_printer -computer $computer | Select-Object Name, Drivername, Portname
    }
}

function Get-PrintManagement {

    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 05172019
 
    .DESCRIPTION
    Opens Print Management
    #>


    [CmdletBinding()]
    param (
    )

    printmanagement.msc
}

function Get-PublicIP {

    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 05172019
 
    .DESCRIPTION
    Returns WhoIS public IP info for your location or any specified public IP
 
    .EXAMPLE
    Returns local Public IP Info
 
    Get-PublicIP
 
    .Example
    Returns your Public IP Info
 
    Get-PublicIP -IP 8.8.8.8
 
    .Link
    Clear-DNSClientCache
    Get-DNSClientCache
    Get-NetIPConfiguration
    Get-NetworkStatistics
    Resolve-DNSName
    Test-Netconnection
    #>


    [CmdletBinding()]
    Param (
        [Parameter(Position = 0)]$IP
    )

    $ipinfo = Invoke-RestMethod http://ipinfo.io/$IP
    $PublicIP = @{
        IP       = $ipinfo.ip
        Hostname = $ipinfo.hostname
        City     = $ipinfo.city
        Region   = $ipinfo.region
        country  = $ipinfo.country
        loc      = $ipinfo.loc
        org      = $ipinfo.org
        Phone    = $ipinfo.phone
    }
    $PublicIP.getenumerator() | Sort-Object -property name

}

function Get-Tetris {
    [Console]::Beep(658, 125);
    [Console]::Beep(1320, 500);
    [Console]::Beep(990, 250);
    [Console]::Beep(1056, 250);
    [Console]::Beep(1188, 250);
    [Console]::Beep(1320, 125);
    [Console]::Beep(1188, 125);
    [Console]::Beep(1056, 250);
    [Console]::Beep(990, 250);
    [Console]::Beep(880, 500);
    [Console]::Beep(880, 250);
    [Console]::Beep(1056, 250);
    [Console]::Beep(1320, 500);
    [Console]::Beep(1188, 250);
    [Console]::Beep(1056, 250);
    [Console]::Beep(990, 750);
    [Console]::Beep(1056, 250);
    [Console]::Beep(1188, 500);
    [Console]::Beep(1320, 500);
    [Console]::Beep(1056, 500);
    [Console]::Beep(880, 500);
    [Console]::Beep(880, 500);
}

function Get-UserDisabledMailboxes {
    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 05172019
 
    .DESCRIPTION
    Create a csv list for mailboxes associated with disabled AD Accounts
 
    .NOTES
    Requires the Active Directory module and must be run from the Exchange Server
 
    .Link
    Get-EndpointReport
    #>


    [CmdletBinding()]

    Param (
    )

    Get-User -RecipientTypeDetails UserMailbox |
    Where-Object { $_.UserAccountControl -like "*accountdisabled*" }
}

function Get-UserReport {

    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 05172019
 
    .DESCRIPTION
    Create a report of Active Directory users
 
    .NOTES
    Requires Active Directory Module
 
    .Example
    Specify is where the report is to be saved.
 
    Get-UserReport -path C:\UserReport.csv
    #>


    [CmdletBinding()]

    Param (
    )

    Import-Module ActiveDirectory

    Get-ADUser -Filter * -properties * |
    Select-Object CN, DistinguishedName, SamAccountName, Modified, PasswordLastSet, PasswordNeverExpires, LockedOut, LastBadPasswordAttempt, BadLogonCount, Created, EmailAddress, { $_.proxyAddresses }, mailNickname, Enabled, HomeDirectory, HomeDrive
}

Function Get-VirtualDirectories {

    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 007022019
 
    .DESCRIPTION
    Returns a list of Virtual Directories
 
    .NOTES
    Requires the Microsoft Exchange module.
 
    .Link
    Set-VirtualDirectories
    #>


    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]$server
    )

    Write-Host "Powershell Virtual Directories"   -Foregroundcolor Green
    Get-PowerShellVirtualDirectory -server $server | Format-List internalurl, externalurl
    Write-Host "Active-Sync Virtual Directories"  -Foregroundcolor Green
    Get-ActiveSyncVirtualDirectory -server $server | Format-List internalurl, externalurl
    Write-Host "Web Services Virtual Directories"    -Foregroundcolor Green
    Get-WebServicesVirtualDirectory -server $server | Format-List internalurl, externalurl
    Write-Host "OWA Virtual Directories"    -Foregroundcolor Green
    Get-OwaVirtualDirectory -server $server | Format-List internalurl, externalurl
    Write-Host "AutoDiscover Virtual Directories"   -Foregroundcolor Green
    Get-AutodiscoverVirtualDirectory -server $server | Format-List internalurl, externalurl
    Write-Host "ECP Virtual Directories"    -Foregroundcolor Green
    Get-EcpVirtualDirectory -server $server | Format-List internalurl, externalurl
    Write-Host "OAB Virtual Directories"    -Foregroundcolor Green
    Get-OABvirtualDirectory -server $server | Format-List internalurl, externalurl
    Write-Host "MAPI Virtual Directories"    -Foregroundcolor Green
    get-mapivirtualdirectory -server $server | Format-List internalurl, externalurl
}

function Get-Weather {
    <#
    .Synopsis
    Modified 05182019
    Taylor Lee
    Made Using api from http://wttr.in/
 
    .Description
    Shows weather for a location or the moon phase
 
    .Notes
    For help modifying the function
 
    http://wttr.in/:help
 
    https://winaero.com/blog/get-weather-forecast-powershell/
 
    .Example
    Multiple Location Options Available
 
    Get-Weather -Location houston+texas
 
    paris # city name
    Eiffel+tower # any location
    muc # airport code (3 letters)
    94107 # area codes
    moon # Moon phase (add ,+US or ,+France for these cities)
    moon@2016-10-25 # Moon phase for the date (@2016-10-25)
 
    .Link
    Connect-SSH
    Enable-PSRemoting
    Enable-Remoting
    #>


    [Cmdletbinding()]
    Param(
        [Parameter(Mandatory = $true)]$Location
    )

    (Invoke-WebRequest http://wttr.in/"$Location"?QF -UserAgent "curl" ).Content
}

function Install-SSH {
    <#
    .SYNOPSIS
    Modified 7/15/2019
    -Taylor Lee
 
    .DESCRIPTION
    Use this function on a local or remote endpoint to enable openssh.
 
    Use PSRemoting to run the command on a remote endpoint.
 
    .EXAMPLE
    Enable-OpenSSH features but don't set the services to Automatic
 
    Install-OpenSSH
 
    .EXAMPLE
    Enable-OpenSSH features and set the services to Automatic
 
    Install-OpenSSH -AutoServices
    #>

    [CmdletBinding(SupportsShouldProcess)]
    [Alias ('Install-OpenSSH')]

    Param (
        [Parameter(Mandatory = $true, ParameterSetName = 'InstallFromFile')]
        [switch]$InstallFromScript,
        [Parameter(Mandatory = $true, ParameterSetName = 'InstallAsFeature')]
        [switch]$InstallAsFeature,
        [Parameter(Mandatory = $false, ParameterSetName = 'InstallAsFeature')]
        [Parameter(Mandatory = $false, ParameterSetName = 'InstallFromFile')]
        [switch]$AutoServices,
        [Parameter(Mandatory = $false, ParameterSetName = 'InstallAsFeature')]
        [Parameter(Mandatory = $false, ParameterSetName = 'InstallFromFile')]
        [switch]$StartServices
    )

    #Check For Admin Privleges
    Get-Elevation

    if ($InstallAsFeature) {
        # Install the OpenSSH Client
        Add-WindowsCapability -Online -Name OpenSSH.Client*
        # Install the OpenSSH Server
        Add-WindowsCapability -Online -Name OpenSSH.Server*
    }

    if ($InstallFromScript) {
        #Install winssh from github
        Write-Host "Installing from Github" -ForegroundColor Green
        $url = "https://github.com/PowerShell/Win32-OpenSSH/releases/download/v8.0.0.0p1-Beta/OpenSSH-Win32.zip"
        $zipfile = "c:\winssh.zip"
        $outpath = "c:\Winssh"
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::TLS12
        Invoke-WebRequest -Uri $url -OutFile $zipfile
        Invoke-Unzip $zipfile $outpath
        Remove-Item $zipfile -force
        . $outpath\OpenSSH-Win32\install-sshd.ps1
    }

    if ($StartServices) {
        #Enable the openssh server services
        Start-Service sshd
        Start-Service SSH-Agent
    }

    if ($AutoServices) {
        #Set services to start Automnatically
        Set-Service -Name sshd -StartupType 'Automatic'
        Set-Service -Name SSH-Agent -StartupType 'Automatic'
    }

    #Set default openssh shell to powerhsell
    $ErrorActionPreference = 'Silentlycontinue'
    New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -PropertyType String -Force
    $ErrorActionPreference = 'Continue'

}

function Invoke-ServiceRecovery {

    <#
    .SYNOPSIS
        -Taylor Lee
        Modified 06252019
    .DESCRIPTION
        Restart one or multiple services that share a part of a Service Displayname
 
        The purpose of this command is recover from issues with widely distributed services. Example would be an antivirus service or Remote Access Agents providing trouble.
    .EXAMPLE
        Restart specified service on all domain endpoints
 
        Invoke-ServiceRecovery -DisplayNameLike Kaseya
 
    .EXAMPLE
        Restart specified service on all remaining endpoints using the failed endpoints log.
 
        Invoke-ServiceRecovery -DisplayNameLike Kaseya -FromLog .\servicerecovery_log_0911.txt
 
    .NOTES
        Must be Run from a DC or have the ActiveDirectory Module imported
    #>


    Param (
        [Parameter(Mandatory = $true)]$DisplayNameLike,
        [Parameter(Mandatory = $false)]$FromLog
    )


    #Check For Admin Privleges
    Get-Elevation

    #Resuming recovery from a Logfile
    if ($FromLog -ne $null) {
        #Restart Services
        Get-Content $FromLog |
        ForEach-Object {
            try {
                Write-Host "Restarting Services with DisplayNameLike $DisplayNameLike on: " -ForegroundColor Green -NoNewline
                Write-Host "$_" -ForegroundColor Cyan

                Get-Service -computername $_ | Where-Object { $_.displayname -like "*$DisplayNameLike*" } | Restart-Service -Force
            }
            catch {
                $trim0 = $_
                $trim1 = $trim0 -replace ("Cannot open Service Control Manager on computer '", "")
                $trimout = $trim1 -replace ("'. This operation might require other privileges.", "")
                $trimout | Out-File $env:USERPROFILE\desktop\ServiceRecovery_Log.txt -Append
            }
        }
    }

    else {
        #Restart Services
        foreach ($computer in Get-ADComputer -Filter { (Enabled -eq $true) } | Sort-Object name | Select-Object -ExpandProperty name) {
            try {
                Write-Host "Restarting Services with DisplayNameLike $DisplayNameLike on: " -ForegroundColor Green -NoNewline
                Write-Host "$computer" -ForegroundColor Cyan

                Get-Service -computername $computer | Where-Object { $_.displayname -like "*$DisplayNameLike*" } | Restart-Service -Force
            }
            catch {
                $trim0 = $_
                $trim1 = $trim0 -replace ("Cannot open Service Control Manager on computer '", "")
                $trimout = $trim1 -replace ("'. This operation might require other privileges.", "")
                $trimout | Out-File $env:USERPROFILE\desktop\ServiceRecovery_Log.txt -Append
            }
        }

    }

    #Rename LogFile to Avoid overwrites later
    $Date = Get-Date -Format hhmm
    Rename-Item $env:USERPROFILE\desktop\ServiceRecovery_Log.txt $env:USERPROFILE\desktop\ServiceRecovery_Log_"$Date".txt
}

function New-AuthPolicy {
    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 071219
 
    .DESCRIPTION
    Used to secure Exchange Online Authentication by creating authentication policies
 
    Use of Modern Authentication Only is important for securing against Password Spray Attacks. New attacks on Basic authentication allow for taking control of an Exchange Online account by simply sending a malicious link to a target.
 
    Authentication Policies that are created are named...
    "Modern Auth Only"
    "Basic Auth Allowed"
 
    .EXAMPLE
    Creates two Authentication Policies. One Basic and One Modern.
 
    Set-AuthPolicy -CreatePolicies
 
    .NOTES
    Requires the Exchange Online module be installed, imported, and Connected.
 
    .LINK
    Get-AuthPolicy
    Set-AuthPolicy
    #>

    [CmdletBinding()]
    Param (
    )

    #create Authentication Policies
    New-AuthenticationPolicy -Name "Modern Auth Only"
    New-AuthenticationPolicy -Name "Basic Auth Allowed"

    #Allow Basic Auth Policy Parameters
    $Params = @{
        AllowBasicAuthActiveSync           = $true
        AllowBasicAuthAutodiscover         = $true
        AllowBasicAuthImap                 = $true
        AllowBasicAuthMapi                 = $true
        AllowBasicAuthOfflineAddressBook   = $true
        AllowBasicAuthOutlookService       = $true
        AllowBasicAuthPop                  = $true
        AllowBasicAuthPowershell           = $true
        AllowBasicAuthReportingWebServices = $true
        AllowBasicAuthRpc                  = $true
        AllowBasicAuthSmtp                 = $true
        AllowBasicAuthWebServices          = $true
        Identity                           = "Basic Auth Allowed"
    }
    Set-AuthenticationPolicy @Params
}

function Remove-All {

    <#
    .Synopsis
    -Taylor Lee
    Modified 06192019
 
    .Description
    This Command removes log files, temp files, and empties the recycle bin. Access denied errors do not indicate a failue of the script. Run for the local or a remote PC.
 
    .EXAMPLE
    Free up space on the local computer
 
    Remove-All
 
    .EXAMPLE
    Free up space on a remote PC. May be more effective if run locally depending on in place security.
 
    Remove-All -Computer JackPC10
 
    .Link
    Remove-DisabledADProfiles
    Remove-OlderThan
    Remove-Path
    #>


    [CmdletBinding(SupportsShouldProcess)]
    param (
        [Parameter(Mandatory = $false)]$computer
    )


    #Check For Admin Privleges
    Get-Elevation

    #Statement of Free Space before Cleaning
    Write-Host " "
    Write-Host "Free Space Before Cleaning" -ForegroundColor Yellow
    Get-CimInstance win32_logicaldisk -filter "drivetype=3" -computer $computer |
    Format-Table -Property DeviceID, Volumename, `
    @{Name = "SizeGB"; Expression = { [math]::Round($_.Size / 1GB) } }, `
    @{Name = "FreeGB"; Expression = { [math]::Round($_.Freespace / 1GB, 2) } }, `
    @{Name = "PercentFree"; Expression = { [math]::Round(($_.Freespace / $_.size) * 100, 2) } }

    #Statement that the function is freeing up space
    Write-Host "Freeing up space. Enjoy your Coffee!" -BackgroundColor Black -ForegroundColor Green

    #Free up space on the local or remote computer
    if ($computer -ne $null) {
        $ErrorActionPreference = 'SilentlyContinue'

        Get-Service -ComputerName $computer TrustedInstaller | Stop-Service -Force
        Get-ChildItem -path "\\$computer\C$\windows\logs" -Include '*.log' -Recurse -force | Remove-Item -force -Recurse
        Get-ChildItem -path "\\$computer\C$\windows\logs" -Include '*.cab' -Recurse -force | Remove-Item -force -Recurse
        Get-ChildItem -path "\\$computer\C$\ProgramData\Microsoft\Windows\WER" -Include '*.*' -Recurse -force | Remove-Item -force -Recurse
        Get-ChildItem -path "\\$computer\C$\$recycle.bin" -Include '*' -Recurse -force | Remove-Item -force -Recurse
        Get-ChildItem -path "\\$computer\C$\Users\*\AppData\Local\Google\Chrome\User Data\Default\Cache\" -include '*.*' -Recurse -force | Remove-Item -force -Recurse
        Get-ChildItem -path "\\$computer\C$\Users\*\AppData\Local\Microsoft\Terminal Server Client\" -include '*.*' -Recurse -force | Remove-Item -force -Recurse
        $tempfolders = @("\\$computer\C$\Windows\Temp\*", "\\$computer\C$\Windows\Prefetch\*", "\\$computer\C$\Documents and Settings\*\Local Settings\temp\*", "\\$computer\C$\Users\*\Appdata\Local\Temp\*")
        Remove-Item $tempfolders -force -recurse
        $tempinternetfolders = @("\\$computer\C$\Users\*\Appdata\Local\Microsoft\Windows\INetCache\*", "\\$computer\C$\Users\*\Appdata\Local\Microsoft\Windows\Cookies\*", "\\$computer\C$\Users\*\AppData\Local\Microsoft\Windows\Temporary Internet Files\*.*")
        Remove-Item $tempinternetfolders -force -recurse
        Get-Service -ComputerName $computer -Name servicename | Start-Service

        $ErrorActionPreference = 'Continue'

        Write-Host " "
        Write-Host "Free Space After Cleaning" -ForegroundColor Yellow
        Get-CimInstance win32_logicaldisk -filter "drivetype=3" -computer $computer |
        Format-Table -Property DeviceID, Volumename, `
        @{Name = "SizeGB"; Expression = { [math]::Round($_.Size / 1GB) } }, `
        @{Name = "FreeGB"; Expression = { [math]::Round($_.Freespace / 1GB, 2) } }, `
        @{Name = "PercentFree"; Expression = { [math]::Round(($_.Freespace / $_.size) * 100, 2) } }
    }

    else {
        $ErrorActionPreference = 'SilentlyContinue'

        Stop-Service TrustedInstaller -Force
        Get-ChildItem -path "C:\windows\" -Include '*.log' -Recurse -force | Remove-Item -force -Recurse
        Get-ChildItem -path "C:\windows\logs" -Include '*.cab' -Recurse -force | Remove-Item -force -Recurse
        Get-ChildItem -path "C:\ProgramData\Microsoft\Windows\WER" -Include '*.*' -Recurse -force | Remove-Item -force -Recurse
        Get-ChildItem -path "c:\$recycle.bin" -Include '*' -Recurse -force | Remove-Item -force -Recurse
        Get-ChildItem -path "C:\Users\*\AppData\Local\Google\Chrome\User Data\Default\Cache\" -include '*.*' -Recurse -force | Remove-Item -force -Recurse
        Get-ChildItem -path "C:\Users\*\AppData\Local\Microsoft\Terminal Server Client\" -include '*.*' -Recurse -force | Remove-Item -force -Recurse
        $tempfolders = @("C:\Windows\Temp\*", "C:\Windows\Prefetch\*", "C:\Documents and Settings\*\Local Settings\temp\*", "C:\Users\*\Appdata\Local\Temp\*")
        Remove-Item $tempfolders -force -recurse
        $tempinternetfolders = @("C:\Users\*\Appdata\Local\Microsoft\Windows\INetCache\*", "C:\Users\*\Appdata\Local\Microsoft\Windows\Cookies\*", "C:\Users\*\AppData\Local\Microsoft\Windows\Temporary Internet Files\*.*")
        Remove-Item $tempinternetfolders -force -recurse
        powercfg.exe /hibernate off
        Remove-Item c:\hiberfil.sys -force -ErrorAction
        Start-Service TrustedInstaller

        $ErrorActionPreference = 'Continue'

        Write-Host " "
        Write-Host "Free Space After Cleaning" -ForegroundColor Yellow
        Get-CimInstance win32_logicaldisk -filter "drivetype=3" -computer $computer |
        Format-Table -Property DeviceID, Volumename, `
        @{Name = "SizeGB"; Expression = { [math]::Round($_.Size / 1GB) } }, `
        @{Name = "FreeGB"; Expression = { [math]::Round($_.Freespace / 1GB, 2) } }, `
        @{Name = "PercentFree"; Expression = { [math]::Round(($_.Freespace / $_.size) * 100, 2) } }
    }

}

function Remove-DisabledADProfiles {

    <#
    .Synopsis
    -Taylor Lee
    Modified 05172019
 
    .Description
    This function leverages PSRemoting to import the AD module a active domain controller.
    It will then parse through existing profiles on the local machine to make sure they don't belong to disabled or missing Active Directory Accounts
    If a prfoile mathces a missing or disable Active Directroy account it will be deleted on the local client.
 
    .Notes
    This function requires Powershell Remoting be enabled on the leveraged domain controller. If PSRemoting is disabled run the command <Enable-PSRemoting -force> on the domain controller
 
    .EXAMPLE
    Use Computername to specify the Domain Controller to be queried for active domain accounts
 
    Remove-DisabledADProfiles -domaincontroller DomainControllerDNSName
 
    .Link
    Remove-All
    Remove-OlderThan
    Remove-Path
    #>


    [CmdletBinding()]

    Param (
        [Parameter(Mandatory = $true)]$domaincontroller
    )

    #Check For Admin Privleges
    Get-Elevation

    $DCSession = New-PSSession -Computername $domaincontroller
    Invoke-Command -Command { Import-Module ActiveDirectory } -Session $DCSession
    Import-PSSession -Session $DCSession -Module ActiveDirectory -allowclobber

    $profiles = Get-WmiObject -Class Win32_UserProfile
    foreach ($prof in $profiles) {
        $sid = $prof.sid
        $ADUser = Get-ADUser -Filter * | Where-Object sid -eq $sid
        if ($ADUser.enabled -eq $false) {
            #delete profile
            "Delete $($ADUser.name)"
            $prof.delete()
        }


    }

}

function Remove-OlderThan {

    <#
    .Synopsis
    -Taylor Lee
    Modified 05172019
 
    .Description
    This scripts function is to delete files and folders older than x days recursivley.
 
    .Example
    Delete-OlderThan -Path "C:\Folder" -DaysBack "-90"
 
    .Link
    Remove-All
    Remove-DisabledADProfiles
    Remove-Path
    #>


    Param (
        [Parameter(Mandatory = $true)]$Path,
        [Parameter(Mandatory = $true)][ValidateScript( { $_ -lt 0 })][int]$Daysback,
        [Parameter(Mandatory = $false)][Switch]$Recurse
    )

    #Check For Admin Privleges
    Get-Elevation

    if ($Recurse) {
        $CurrentDate = Get-Date
        $DatetoDelete = $CurrentDate.AddDays($Daysback)
        Get-ChildItem $Path -Recurse | Where-Object { $_.LastWriteTime -lt $DatetoDelete } | Remove-Item -Force
    }

    else {
        $CurrentDate = Get-Date
        $DatetoDelete = $CurrentDate.AddDays($Daysback)
        Get-ChildItem $Path | Where-Object { $_.LastWriteTime -lt $DatetoDelete } | Remove-Item -Force
    }

}

function Remove-Path {

    <#
    .Synopsis
    -Taylor Lee
    Modified 05172019
 
    .DESCRIPTION
    This command deletes all files recursively in a path that match the included filename.
 
    .EXAMPLE
    Specify the parent folder from which the command runs and specify file names to include. Wildcards are supported.
 
    Remove-Path -path c:\Folder -include "*.logs"
 
    .Link
    Remove-All
    Remove-DisabledADProfiles
    Remove-OlderThan
    #>


    [CmdletBinding(SupportsShouldProcess)]

    Param (
        [Parameter(Mandatory = $true)]$Path,
        [Parameter(Mandatory = $true)]$Include
    )

    #Check For Admin Privleges
    Get-Elevation

    Get-ChildItem -path "$Path" -Include "$Include" -Recurse -force | Remove-Item -force -Recurse
}

function Remove-PrintQueue {

    <#
    .Synopsis
    -Taylor Lee
    Modified 05172019
 
    .DESCRIPTION
    This command clears print queues for all printers
    #>


    [CmdletBinding(SupportsShouldProcess)]
    param (
    )

    $printers = Get-Printer
    foreach ($printer in $printers) {
        $printjobs = Get-PrintJob -PrinterObject $printer
        foreach ($printjob in $printjobs) {
            Remove-PrintJob -InputObject $printjob
        }
    }

}

function Reset-NetworkAdapter {

    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 05172019
 
    .DESCRIPTION
    Reset a specified interface
 
    .EXAMPLE
    Reset-NetworkAdapter -interface "Local Area Connection"
 
    .Link
    Reset-NetworkStack
    #>


    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]$Interface
    )

    #Check For Admin Privleges
    Get-Elevation

    netsh.exe interface set interface $Interface admin=disable
    netsh.exe interface set interface $Interface admin=enable
}

function Reset-NetworkStack {

    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 05172019
 
    .DESCRIPTION
    Resets the TCP/IP and Winsock Stacks
 
    .Link
    Reset-NetworkAdapter
    #>


    [CmdletBinding()]
    param (
    )

    #Check For Admin Privleges
    Get-Elevation

    netsh.exe winsock reset
    netsh.exe int ip reset
    netsh.exe int ipv4 reset reset.log
    netsh.exe int ipv6 reset reset.log
    Write-Host "You need to restart the computer now"  -foregroundcolor yellow
}

function Restart-Endpoint {

    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 05172019
 
    .DESCRIPTION
    Sets a countdown to restart the Endpoint. The command uses a multiplier set to 1 hour.
    You can use decimals to return shorter than an hour restart times or get X hours and X minutes.
 
    .NOTES
    The parameter must be typed when entering the command and not after. If you typed the command and then entered the parameter when prompted the command will fail.
 
    When using decimal values understand that the value is multiplying against the number of seconds in an hour.
    So all multiplication needs to be done as a fraction of 1. Don't try thinking that it needs to be done against the value of 60 for seconds or hours.
    View the Examples for clarification.
 
    .EXAMPLE
    Restarts the Endpoint in 5 Hours
 
    Restart-Endpoint -Hours 5
 
    .EXAMPLE
    Restarts the Endpoint in 5 hours and 15 minutes
 
    Restart-Endpoint -Hours 5.25
 
    .EXAMPLE
    Restarts the Endpoint in 15 minutes
 
    Restart-Endpoint -Hours 0.25
 
    .Link
    Get-DCLockoutEvents2
    Get-LockedAccounts
    Get-PasswordExpired
    Unlock-Account
    Unlock-AllAccounts
    #>


    [CmdletBinding()]

    Param (
        [Parameter(Mandatory = $true)][int]$Hours
    )

    $Hoursmultiplied = $Hours * 3600

    shutdown.exe /r /t $Hoursmultiplied
}


function Set-AuthPolicy {
    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 071219
 
    .DESCRIPTION
    Used to secure Exchange Online Authentication by applying authentication policies
 
    Use of Modern Authentication Only is important for securing against Password Spray Attacks. New attacks on Basic authentication allow for taking control of an Exchange Online account by simply sending a malicious link to a target.
 
    .EXAMPLE
    Apply "Modern Auth Only" To all Exchange Online Mailboxes
 
    Set-AuthPolicy -ApplyAllModern
 
    .EXAMPLE
    Apply "Modern Auth Only" Policy to a single Mailbox or multiple that have a Display Name Like "John Smith".
 
    Set-AuthPolicy -ApplyPolicySingle -DisplayNameLike "John Smith" -Policy "Modern Auth Only"
 
    .EXAMPLE
    Apply "Modern Auth Only" Policy to all mailboxes with a $null policy
 
    Set-AuthPolicy -ApplytoNull -Policy "Modern Auth Only"
 
    .NOTES
    Requires the Exchange Online module be installed, imported, and Connected.
 
    .LINK
    Get-AuthPolicy
    New-AuthPolicy
    #>

    [CmdletBinding(SupportsShouldProcess)]
    Param (
        [Parameter(Mandatory = $True, ParameterSetName = 'Apply All Modern')]
        [switch]$ApplyAllModern,
        [Parameter(Mandatory = $True, ParameterSetName = 'Apply All Basic')]
        [switch]$ApplyAllBasic,
        [Parameter(Mandatory = $True, ParameterSetName = 'Apply Policy Single Account')]
        [switch]$ApplyPolicySingle,
        [Parameter(Mandatory = $True, ParameterSetName = 'Apply Policy Single Account')]
        $DisplayNameLike,
        [Parameter(Mandatory = $True, ParameterSetName = 'Apply Policy Single Account')]
        [Parameter(Mandatory = $True, ParameterSetName = 'Apply Policy for Null')]
        [ValidateSet ('Modern Auth Only', 'Basic Auth Only')]
        $Policy,
        [Parameter(Mandatory = $True, ParameterSetName = 'Apply Policy for Null')]
        [switch]$ApplytoNull
    )

    if ($ApplyAllModern) {
        #Apply Modern Authentication Policy
        $v1 = Get-User -ResultSize unlimited -Filter *
        $v2 = $v1.MicrosoftOnlineServicesID
        $v2 | ForEach-Object { Set-User -Identity $_ -AuthenticationPolicy "Modern Auth Only" } -Verbose

        #Apply Authentication Policy immediately
        $v2 | ForEach-Object { Set-User -Identity $_ -STSRefreshTokensValidFrom $([System.DateTime]::UtcNow) } -Verbose
    }

    if ($ApplyAllBasic) {
        #Apply Modern Authentication Policy
        $v1 = Get-User -ResultSize unlimited -Filter *
        $v2 = $v1.MicrosoftOnlineServicesID
        $v2 | ForEach-Object { Set-User -Identity $_ -AuthenticationPolicy "Basic Auth Only" } -Verbose

        #Apply Authentication Policy immediately
        $v2 | ForEach-Object { Set-User -Identity $_ -STSRefreshTokensValidFrom $([System.DateTime]::UtcNow) } -Verbose
    }

    if ($ApplyPolicySingle) {
        #Apply Policy to a single Account
        $v1 = Get-User -ResultSize unlimited -Filter "DisplayName -like '$DisplayNameLike*'"
        $v2 = $v1.MicrosoftOnlineServicesID
        $v2 | ForEach-Object { Set-User -Identity $_ -AuthenticationPolicy "$Policy" }

        #Apply Authentication Policy immediately
        $v2 | ForEach-Object { Set-User -Identity $_ -STSRefreshTokensValidFrom $([System.DateTime]::UtcNow) } -Verbose
    }

    if ($ApplytoNull) {
        #Apply Policy to accounts with No Policy
        $v1 = Get-Recipient -RecipientTypeDetails UserMailbox -ResultSize Unlimited | get-user | Where-Object { $null -eq $_.AuthenticationPolicy }
        $v2 = $v1.MicrosoftOnlineServicesID
        $v2 | ForEach-Object { Set-User -Identity $_ -AuthenticationPolicy "$Policy" }

        #Apply Authentication Policy immediately
        $v2 | ForEach-Object { Set-User -Identity $_ -STSRefreshTokensValidFrom $([System.DateTime]::UtcNow) } -Verbose
    }
}

function Set-Password {

    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 05172019
 
    .DESCRIPTION
    Sets a Active Directory Password and provides an option to require a password change on login
 
    .NOTES
    Requires the Active Directory Module
 
    .EXAMPLE
    Specifies the username being set and then prompts for a password.
 
    Set-Password -username domain\username
    #>

    [CmdletBinding()]

    Param (
        [Parameter(Mandatory = $true)]
        [ValidateScript( { if ($_ -notlike "*\*") { throw "Username must be in the following format Domain\Username" } else { $true } })]
        $Username,
        [Parameter(Mandatory = $true)][SecureString]$Password
    )

    Import-Module ActiveDirectory

    Set-ADAccountPassword -identity $username -Reset -NewPassword $Password

    $Prompt = Read-Host "Require a Password Change? Type Yes or No."

    if ($Prompt -eq 'Yes') {
        Set-ADUser -Identity $Username -ChangePasswordAtLogon $true
    }
    else {
        Write-Host "You specified no" -ForegroundColor Yellow
    }
}

function Set-UAC {

    <#
    .Synopsis
    -Taylor Lee
    Modified 07062019
 
    .Description
    This function can Enable/Disable UserAccountControl entirely or just the Prompt Behaviour
 
    .Example
    Disabled UAC Prompting for Admins, but keeps UAC enabled
 
    Set-UACState -DisablePrompt
 
    .Example
    Disabled UAC Entirely
 
    Set-UACState -Disable
 
    .Example
    Enable UAC Entirely
 
    Set-UACState -Enable
    #>


    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, ParameterSetName = 'Disable')][switch]$Disable,
        [Parameter(Mandatory = $true, ParameterSetName = 'DisablePrompt')][switch]$DisablePrompt,
        [Parameter(Mandatory = $true, ParameterSetName = 'Enable')][switch]$Enable
    )

    #Check For Admin Privleges
    Get-Elevation

    if ($Disable) {
        reg.exe add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" /f /v "ConsentPromptBehaviorAdmin" /t reg_dword /d 0
        reg.exe add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" /f /v "EnableLUA" /t reg_dword /d 0
    }

    if ($DisablePrompt) {
        reg.exe add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" /f /v "ConsentPromptBehaviorAdmin" /t reg_dword /d 0
    }

    if ($Enable) {
        reg.exe add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" /f /v "ConsentPromptBehaviorAdmin" /t reg_dword /d 2
        reg.exe add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" /f /v "EnableLUA" /t reg_dword /d 1
    }
}

function Set-VirtualDirectories {
    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 07022019
 
    .DESCRIPTION
    Configure Virtual Directories for Exchange
 
    .Example
    Specifiy the mail server directories are being set on and the url that matches the mail records.
 
    Set-VirtualDirectories -Servername exch2016-01 -url mail.domain.com
 
    .Link
    Get-VirtualDirectories
    #>


    [cmdletbinding()]
    param (
        [Parameter(Mandatory = $true)]$servername,
        [Parameter(Mandatory = $true)]$url
    )



    #Set Virtual Directories
    ###Set Activesync
    Get-ActiveSyncVirtualDirectory -server $servername | Set-ActiveSyncVirtualDirectory -Internalurl https://$url/Microsoft-Server-ActiveSync -externalurl https://$url/Microsoft-Server-ActiveSync

    ###Set Web Services
    Get-WebServicesVirtualDirectory -server $servername | Set-WebServicesVirtualDirectory -Internalurl https://$url/ews/exchange.asmx -externalurl https://$url/ews/exchange.asmx

    ###Set OWA
    Get-OwaVirtualDirectory -server $servername | Set-OwaVirtualDirectory -Internalurl https://$url/owa -externalurl https://$url/owa

    ###Set Autodiscover
    Set-ClientAccessServer -Identity $servername -AutoDiscoverServiceInternalUri https://$url/Autodiscover/Autodiscover.xml

    Get-AutodiscoverVirtualDirectory -server $servername | Set-AutodiscoverVirtualDirectory -Internalurl https://$url/Autodiscover/Autodiscover.xml -externalurl https://$url/Autodiscover/Autodiscover.xml

    ###Set Ecp
    Get-EcpVirtualDirectory -server $servername | Set-EcpVirtualDirectory -Internalurl https://$url/ecp -externalurl https://$url/ecp

    ###Set OAB
    Get-OABvirtualDirectory -server $servername | Set-OABvirtualDirectory -Internalurl https://$url/oab -externalurl https://$url/oab

    #Set MApi Virtual Directories
    get-mapivirtualdirectory -server $servername | Set-MapiVirtualDirectory -InternalUrl ttps://$url/mapi -externalUrl ttps://$url/mapi
}

function Start-AzureSync {

    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 05172019
 
    .DESCRIPTION
    Starts a local Active Directory sync to Azure Active Directory.
 
    .NOTES
    Must be run from the Domain Controller that has Azure AD Connect.
 
    .Example
    Performs a full sync with Azure Active Directory
 
    Start-AzureSync -Policy Initial
 
    .EXAMPLE
    Performs an incrmental sync with Azure Active Directroy
 
    Start-AzureSync -Policy Delta
    #>


    [CmdletBinding()]

    Param (
        [Parameter(Mandatory = $true)]
        [validateset ("delta", "initial")]
        $Policy
    )

    Start-ADSyncSyncCycle -PolicyType $Policy
}

function Start-Iperf {
    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 06262019
    .DESCRIPTION
    Setup and iperf server or client connection for testing connection speeds
 
    .EXAMPLE
    Setup a iperf server connection
 
    Start-Iperf -server -port 10555
 
    .EXAMPLE
    Initiate a client bandwidth test
 
    Start-Iperf -client -serverip 0.0.0.0 -port 10555
 
    .EXAMPLE
    Initiate a client bandwidth test
 
    Start-Iperf -Client -serverip 0.0.0.0 --port 10555 udp
    #>


    [CmdletBinding()]
    Param (

        [Parameter(Mandatory = $true, ParameterSetName = 'Server')][Switch]$server,
        [Parameter(Mandatory = $true, ParameterSetName = 'Client')][switch]$client,
        [Parameter(Mandatory = $false, ParameterSetName = 'Client')][Switch]$udp,
        [Parameter(Mandatory = $true, ParameterSetName = 'Client')]$serverip,
        [Parameter(Mandatory = $true, ParameterSetName = 'Client')]
        [Parameter(Mandatory = $true, ParameterSetName = 'Server')]
        $port
    )

    $AdminConsole = [bool](([System.Security.Principal.WindowsIdentity]::GetCurrent()).groups -match "S-1-5-32-544")

    if ($AdminConsole -like "False*") {
        Write-Warning "You need to run Powerhsell as an admin to use this function!"
        Break
    }

    if ($server) {
        iperf3.exe -s -p $port
    }

    if ($client) {
        if ($udp) {
            iperf3.exe -c $serverip -p $port -u -b 0
        }

        else {
            iperf3.exe -c $serverip -p $port
        }
    }
}

function Uninstall-Application {
    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 06282019
    .DESCRIPTION
    Added a graphic uninstaller using Out-Gridview.
 
    This makes it easy to call the uninstall string for applications from an elevated command prompt.
 
    This removes the requirement to change accounts for uninstalling an application when otherwise it would of been faster to do so.
 
    .EXAMPLE
    Run the command, Select and application from the list, and click ok.
 
    Uninstall-Application
 
    .Link
    Get-Applications
    #>


    [Cmdletbinding()]
    [alias("Remove-Application")]
    Param (
    )

    #Check For Admin Privleges
    Get-Elevation

    #Provide the application to be uninstalled
    Write-Host ""
    Write-Host "Find the Out-Gridview window and select an application to uninstall!" -ForegroundColor Yellow
    $out = Get-Applications | Out-GridView -passthru -title "Select an Application to Uninstall"

    #If the uninstaller uses msiexec, this will parse the string to be readable by the console.
    if ($out.uninstallstring -like "msiexec*") {
        $out1 = $out.uninstallstring -replace ('{', ' "{')
        $out2 = $out1 -replace ('}', '}"')
        $arguments = $out2 -replace ('msiexec.exe', '')
        Write-Host "Find the uninstall window if exists to finish the uninstall" -Foregroundcolor green
        Write-Host ""
        Start-Process -Filepath msiexec.exe -argumentlist $arguments
    }

    #If not an msiexec installer, this will add quatation marks to avoid issues caused by spaces in the path.
    else {
        $out1 = $out.uninstallstring + '"'
        $filepath = '"' + $out1
        Write-Host "Find the uninstall window if exists to finish the uninstall" -Foregroundcolor green
        Write-Host ""
        Start-Process -Filepath $filepath
    }
}

function Unlock-Account {

    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 05172019
 
    .DESCRIPTION
    Unlocks an Active Directory Account
 
    .NOTES
    Requires the Active Directory Module.
 
    .Example
    Use Get-lockedAccounts to quickly obtain the identity to use in the command.
 
    Get-LockedAccounts
    Unlock-ADAccount -identity JohnD
 
    .Link
    Get-DCLockoutEvents2
    Get-LockedAccounts
    Get-PasswordExpired
    Set-Password
    Unlock-AllAccounts
    #>


    [CmdletBinding()]

    Param (
        [Parameter(Mandatory = $true)]$Username
    )

    Import-Module ActiveDirectory

    Unlock-ADAccount -identity $username

}

function Unlock-AllAccounts {

    <#
    .SYNOPSIS
    -Taylor Lee
    Modified 05172019
 
    .DESCRIPTION
    Unlocks all Active Directory Accounts
 
    .NOTES
    Requires the Active Directory Module.
 
    .Link
    Get-DCLockoutEvents2
    Get-LockedAccounts
    Get-PasswordExpired
    Set-Password
    Unlock-Account
    #>


    [CmdletBinding()]
    Param (
    )

    Search-ADAccount -lockedout | Unlock-ADAccount
}