PowerLogger.psm1

<#
.SYNOPSIS
    Logging Utility
.DESCRIPTION
    Creates Logs to be used within other scripts
.NOTES
    Author: Micah
    Creation Date: 20150112
    Last Modified: 20170202
    Version: 1.8.2

-----------------------------------------------------------------------------------------------------------------
CHANGELOG
-----------------------------------------------------------------------------------------------------------------
    1.0 Initial Release
    1.1 Addition of terminal logging with seperate log level
    1.2 Added Ability to Remove previous log if exists
    1.4 Added Ability to set color of text outputting to console besides the Default
    1.5 Added Master override of colloring for terminal Output
    1.6 Added Sub Sections to script to allow grouping of messages
    1.7 Added CSV Formatting of the Log
        1.7.1 Added ForceCSV to Indivdual Logging Commands
    1.8 Added Email functionlity send-PLLog as well as -emailline logic to include specific line items in email.
        1.8.2 Added ability to remote send Log as well as Added Internal send-pllogging function

-----------------------------------------------------------------------------------------------------------------
TODO
-----------------------------------------------------------------------------------------------------------------
1. Add functionality to only email last log from start
2. Fix error script name and path
3. Pull write logic out of individual functions / re-try if file is open
    #>


function Verify-CSVHeaders
{
param(
[string][Parameter(Mandatory=$true)]$Fullpath,
[boolean][Parameter(Mandatory=$false)]$Overwrote
)
    if($Overwrote -or !(Test-Path $Fullpath))
        {
        Add-Content -path $Fullpath -Value "Time,LogLevel,SubLevel,Message "
        }
}

function Start-Logging()
{
[CmdletBinding()]
param(
    [Parameter(Mandatory=$false)]$ScriptName=$null,
    [Parameter(Mandatory=$false)]$LogPath=$null,
    [validateset("INFO", "DEBUG", "Verbose", "None")]
    [Parameter(Mandatory=$false)]$LoggingLevel="INFO",
    [Parameter(Mandatory=$false)]$ScriptVersion,
    [boolean][Parameter(Mandatory=$false)]$OutputTerminal,
    [validateset("INFO", "DEBUG", "Verbose", "None")]
    [Parameter(Mandatory=$false)]$TerminalLevel="None",
    [switch][Parameter(Mandatory=$false)]$OverWriteLog,
    [validateset("Black","Blue","Cyan","DarkBlue","DarkCyan","DarkGray","DarkGreen","DarkMagenta","DarkRed","DarkYellow","Gray","Green","Magenta","Red","White","Yellow")]
    [Parameter(Mandatory=$false)]$OverRideInfoColor="White",
    [validateset("Black","Blue","Cyan","DarkBlue","DarkCyan","DarkGray","DarkGreen","DarkMagenta","DarkRed","DarkYellow","Gray","Green","Magenta","Red","White","Yellow")]
    [Parameter(Mandatory=$false)]$OverRideVerboseColor="Cyan",
    [validateset("Black","Blue","Cyan","DarkBlue","DarkCyan","DarkGray","DarkGreen","DarkMagenta","DarkRed","DarkYellow","Gray","Green","Magenta","Red","White","Yellow")]
    [Parameter(Mandatory=$false)]$OverRideDEBUGColor="Red",
    [Parameter(Mandatory=$false)][Switch]$WriteCSV
    )

Process{


$ScriptNameOrigin = $MyInvocation.ScriptName
if ($ScriptName -eq $null) # If script name was not set pull from Script
{
try{
$Scriptname = Split-Path $ScriptNameOrigin -Leaf

$ScriptName = $ScriptName.Substring(0,$ScriptName.IndexOf("."))
}
catch{
$ScriptName = Get-Date -Format "yyyymmddhhmm"
$ScriptNameOrigin = $env:TEMP
Write-Host "Unable to find script path... Logging at $ScriptNameOrigin" -ForegroundColor Red
sleep -Seconds 2
}

}

if ($LogPath -eq $null -and $ScriptNameOrigin -eq $env:TEMP)
{
$LogPath = $ScriptNameOrigin
}
else
{
$LogPath = split-path $ScriptNameOrigin -Parent
}


# If requested to write csv make extension CSV
if ($WriteCSV.IsPresent)
    {
    $SCRIPT:Fullpath = $LogPath + "\" + $ScriptName + ".csv"
    }
else
    {
    $SCRIPT:Fullpath = $LogPath + "\" + $ScriptName + ".log"
    }

$Overwrote = $false
$Script:Emailbody = @()
$SCRIPT:ScriptName = $ScriptName
$SCRIPT:LoggingLevel = $LoggingLevel
$SCRIPT:TerminalLogging = $OutputTerminal
$SCRIPT:TerminalLevel = $TerminalLevel
$SCRIPT:InfoColor = $OverRideInfoColor
$SCRIPT:VerboseColor = $OverRideVerboseColor
$SCRIPT:DebugColor = $OverRideDEBUGColor
$SCRIPT:WriteCSV = $WriteCSV.IsPresent

if ($OverWriteLog.IsPresent -and (Test-Path $LogPath))
    {
    Remove-Item $Fullpath
    $Overwrote = $true
    }





IF ($SCRIPT:LoggingLevel -ne "None"){
    # Change format of Header if Write CSV is present
    if ($WriteCSV.IsPresent)
        {
        Verify-CSVHeaders -Fullpath $Fullpath -Overwrote $Overwrote
        Add-Content -Path $Fullpath -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss'),INFO,LOGSTART,`"Started $LoggingLevel for $ScriptName`""
        If ($ScriptVersion -ne $null){Add-Content -Path $Fullpath -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss'),INFO,LOGSTART,`"Script Version: $ScriptVersion`""}
        if ($Overwrote -eq $true){Add-Content -Path $Fullpath -Value "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss'),INFO,LOGSTART,`"Log file has been overwritten`""}
        }
    else
        {
        #Show Logging start time
        Add-content -path $Fullpath -value "____________________________________________________________________________________________________________________"
        Add-Content -Path $Fullpath -Value "Started $LoggingLevel Logging for $ScriptName at $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
        If ($ScriptVersion -ne $null){Add-Content -Path $Fullpath -Value "Script Version: $ScriptVersion"}
        if ($Overwrote -eq $true){Add-Content -Path $Fullpath -Value "Log file has been overwritten"}
        Add-content -path $Fullpath -value "____________________________________________________________________________________________________________________"
        }
}
if ($SCRIPT:TerminalLogging -and $SCRIPT:TerminalLevel -ne "None")
    {
    Write-Host "Started $LoggingLevel Logging for $ScriptName at $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" -ForegroundColor Green
    If ($ScriptVersion -ne $null){Write-Host -Path $Fullpath -Value "Script Version: $ScriptVersion" -ForegroundColor Green}
    Write-Host "____________________________________________________________________________________________________________________" -ForegroundColor Green
    }
}
}

function Write-PLInfo()
{
[CmdletBinding()]
param(
    [Parameter(Mandatory=$true)]$Message,
    [Parameter(Mandatory=$false)]$LogFile=$SCRIPT:Fullpath,
    [Parameter(Mandatory=$false)]$Sublevel = $null,
    [Parameter(Mandatory=$false)][switch]$ForceTerminal,
    [validateset("Black","Blue","Cyan","DarkBlue","DarkCyan","DarkGray","DarkGreen","DarkMagenta","DarkRed","DarkYellow","Gray","Green","Magenta","Red","White","Yellow")]
    [Parameter(Mandatory=$false)]$ForegroundColor = $SCRIPT:InfoColor,
    [Parameter(Mandatory=$false)][switch]$ForceCSV,
    [Parameter(Mandatory=$false)][switch]$emailLine
    )
    $timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
    $originalMessage = $Message
    if ($Sublevel -ne $null)
        {
        $Message = "[$Sublevel]`t`t$Message"
        }
    $output = "$timestamp`t`[INFO]:`t`t$message"

if (($SCRIPT:LoggingLevel -eq "INFO" -or $SCRIPT:LoggingLevel -eq "Debug" -or $SCRIPT:LoggingLevel -eq "Verbose") -and !($SCRIPT:writecsv -or $ForceCSV.IsPresent))
    {
    if($emailLine.IsPresent)
        {
        $script:emailbody += "$output <br>"
        }
    Add-Content -Path $LogFile -Value $output
    }
if (($SCRIPT:TerminalLogging -and $SCRIPT:TerminalLevel -ne "None") -or $ForceTerminal.IsPresent)
    {
    Write-Host $output -ForegroundColor $ForegroundColor
    }
if(($SCRIPT:LoggingLevel -eq "INFO" -or $SCRIPT:LoggingLevel -eq "Debug" -or $SCRIPT:LoggingLevel -eq "Verbose") -and ($SCRIPT:writecsv -or $ForceCSV.IsPresent))
    {
    if($emailLine.IsPresent)
        {
        $script:emailbody += "$output <br>"
        }
    if ($LogFile -like "*.log")
        {
        $LogFile = $LogFile.Replace('.log','.csv')
        }
    Verify-CSVHeaders -Fullpath $LogFile 
    # "Time,LogLevel,SubLevel,Message "
    Add-Content -Path $LogFile -Value "$timestamp,INFO,`"$Sublevel`",`"$originalMessage`""
    }
}

function Write-PLDebug()
{
[CmdletBinding()]
param(
    [Parameter(Mandatory=$true)]$Message,
    [Parameter(Mandatory=$false)]$LogFile=$SCRIPT:Fullpath,
    [Parameter(Mandatory=$false)]$Sublevel = $null,
    [Parameter(Mandatory=$false)][switch]$ForceTerminal,
    [validateset("Black","Blue","Cyan","DarkBlue","DarkCyan","DarkGray","DarkGreen","DarkMagenta","DarkRed","DarkYellow","Gray","Green","Magenta","Red","White","Yellow")]
    [Parameter(Mandatory=$false)]$ForegroundColor = $SCRIPT:DEBUGColor,
    [Parameter(Mandatory=$false)][switch]$ForceCSV,
    [Parameter(Mandatory=$false)][switch]$emailLine
    )
    $timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
    $originalMessage = $Message
    if ($Sublevel -ne $null)
        {
        $Message = "[$Sublevel]`t`t$Message"
        }
    $output = "$timestamp`t`[DEBUG]:`t$message"
if ($SCRIPT:LoggingLevel -eq "Debug"  -and !($SCRIPT:writecsv -or $ForceCSV.IsPresent))
    {
    if($emailLine.IsPresent)
        {
        $script:emailbody += "$output <br>"
        }
    Add-Content -Path $LogFile -Value $output
    }
if (($SCRIPT:TerminalLogging -and $SCRIPT:TerminalLevel -eq "debug") -or $ForceTerminal.IsPresent)
    {
    Write-Host $output -ForegroundColor $ForegroundColor
    }
if ($SCRIPT:LoggingLevel -eq "Debug"  -and ($SCRIPT:writecsv  -or $ForceCSV.IsPresent))
    {
    if($emailLine.IsPresent)
        {
        $script:emailbody += "$output <br>"
        }
    if ($LogFile -like "*.log")
        {
        $LogFile = $LogFile.Replace('.log','.csv')
        }
    Verify-CSVHeaders -Fullpath $LogFile 
    # "Time,LogLevel,SubLevel,Message "
    Add-Content -Path $LogFile -Value "$timestamp,DEBUG,`"$Sublevel`",`"$originalMessage`""
    }
}

function Write-PLVerbose()
{
[CmdletBinding()]
param(
    [Parameter(Mandatory=$true)]$Message,
    [Parameter(Mandatory=$false)]$LogFile=$SCRIPT:Fullpath,
    [Parameter(Mandatory=$false)]$Sublevel = $null,
    [Parameter(Mandatory=$false)][switch]$ForceTerminal,
    [validateset("Black","Blue","Cyan","DarkBlue","DarkCyan","DarkGray","DarkGreen","DarkMagenta","DarkRed","DarkYellow","Gray","Green","Magenta","Red","White","Yellow")]
    [Parameter(Mandatory=$false)]$ForegroundColor = $SCRIPT:VerboseColor,
    [Parameter(Mandatory=$false)][switch]$ForceCSV,
    [Parameter(Mandatory=$false)][switch]$emailLine
    )
    $timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
    $originalMessage = $Message
    if ($Sublevel -ne $null)
        {
        $Message = "[$Sublevel]`t`t$Message"
        }
    $output = "$timestamp`t`[Verbose]:`t$message"
if ($SCRIPT:LoggingLevel -eq "Debug" -or $SCRIPT:LoggingLevel -eq "Verbose" -and !($SCRIPT:writecsv -or $ForceCSV.IsPresent))
    {
    if($emailLine.IsPresent)
        {
        $script:emailbody += "$output <br>" 
        }
    Add-Content -Path $LogFile -Value $output
    }
if (($SCRIPT:TerminalLogging -and ($SCRIPT:TerminalLevel -eq "Debug" -or $SCRIPT:TerminalLevel -eq "Verbose")) -or $ForceTerminal.IsPresent)
    {
    Write-Host $output -ForegroundColor $ForegroundColor
    }
if (($SCRIPT:LoggingLevel -eq "Debug" -or $SCRIPT:LoggingLevel -eq "Verbose")  -and ($SCRIPT:writecsv -or $ForceCSV.IsPresent))
    {
    if($emailLine.IsPresent)
        {
        $script:emailbody += "$output <br>" 
        }
    if ($LogFile -like "*.log")
        {
        $LogFile = $LogFile.Replace('.log','.csv')
        }
    Verify-CSVHeaders -Fullpath $LogFile 
    # "Time,LogLevel,SubLevel,Message "
    Add-Content -Path $LogFile -Value "$timestamp,VERBOSE,`"$Sublevel`",`"$originalMessage`""
    }
}

Function Send-PLLog()
{
    param($From = "PowerLogger<mog.helpdesk@jacobs.com>",
          $To = "Micah.Joiner@Jacobs.com",
          $Subject = "Log File",
          $HTMLMessage = "$null",
          $SMTPServer = "",
          [switch]$dontincludeLog,
          [switch]$Onlyoncondition,
          $condition = 'ERROR',
          $remoteSender = $null)

    if($dontincludeLog.IsPresent) # Dont include the log if we were asked not to
        {
        $logcontents = $null
        }
    else
        {
        $logcontents = Get-Content -Path $SCRIPT:Fullpath
        }

    

    if($script:emailbody[0] -ne $null)
        {
        $HTMLMessage += $script:emailbody
        }
    elseif($Onlyoncondition.IsPresent -and ([string]($logcontents)  -notlike "*$condition*"))
        {
        return
        }

    if ($remoteSender -eq $null)
    {
        Send-pllogging -From $From -To $To -Subject $Subject -HTMLMessage $HTMLMessage -SMTPServer $SMTPServer -LogContents $logcontents -scriptName $SCRIPT:ScriptName
    }
    else
    {
        if(Test-Connection -ComputerName $remoteSender -Quiet -Count 1)
            {
            Invoke-Command -ComputerName $remoteSender -ScriptBlock ${Function:send-pllogging} -ArgumentList $from, $to, $Subject, $HTMLMessage, $SMTPServer, $logcontents, $SCRIPT:ScriptName
            }
    }
    
}

Function Send-pllogging
{
    param($From,
          $To,
          $Subject,
          $HTMLMessage,
          $SMTPServer,
          $LogContents,
          $ScriptName)


              
    # Initialize email
    $MailMessage = New-Object System.Net.Mail.MailMessage
    $SMTPClient = New-Object System.Net.Mail.SMTPClient
    
    
    #Start building message
    $MailMessage.To.Add("$To")
    $MailMessage.From = "$From"
    $MailMessage.Subject = "$Subject"
    $MailMessage.Body = $HTMLMessage
    $MailMessage.IsBodyHTML = $true

    $FileName = "C:\Windows\Temp\$ScriptName.log"
    Add-Content -Value $LogContents -Path $FileName

    #Only add atachment if available
    If($LogContents -ne $null)
    {
        $Attachment = New-Object System.Net.Mail.Attachment($FileName)
        $MailMessage.Attachments.Add($Attachment)
    }

    # Section to send email by pickup directory
    #$SMTPClient.PickupDirectoryLocation = $PickupDirectory
    #$SMTPClient.DeliveryMethod = "SpecifiedPickupDirectory"

    $SMTPClient.Host = $SMTPServer
    $SMTPClient.Send($MailMessage)


    Remove-Item -Path $FileName -Force

}