212 lines
9.1 KiB
PowerShell
212 lines
9.1 KiB
PowerShell
function Write-AuditLog {
|
|
<#
|
|
.SYNOPSIS
|
|
Writes log messages to the console and updates the script-wide log variable.
|
|
.DESCRIPTION
|
|
The Write-AuditLog function writes log messages to the console based on the severity (Verbose, Warning, or Error) and updates
|
|
the script-wide log variable ($script:LogString) with the log entry. You can use the Start, End, and EndFunction switches to
|
|
manage the lifecycle of the logging.
|
|
.INPUTS
|
|
System.String
|
|
You can pipe a string to the Write-AuditLog function as the Message parameter.
|
|
You can also pipe an object with a Severity property as the Severity parameter.
|
|
.OUTPUTS
|
|
None
|
|
The Write-AuditLog function doesn't output any objects to the pipeline. It writes messages to the console and updates the
|
|
script-wide log variable ($script:LogString).
|
|
.PARAMETER BeginFunction
|
|
Sets the message to "Begin [FunctionName] function log.", where FunctionName is the name of the calling function, and adds it to the log variable.
|
|
.PARAMETER Message
|
|
The message string to log.
|
|
.PARAMETER Severity
|
|
The severity of the log message. Accepted values are 'Information', 'Warning', and 'Error'. Defaults to 'Information'.
|
|
.PARAMETER Start
|
|
Initializes the script-wide log variable and sets the message to "Begin [FunctionName] Log.", where FunctionName is the name of the calling function.
|
|
.PARAMETER End
|
|
Sets the message to "End Log" and exports the log to a CSV file if the OutputPath parameter is provided.
|
|
.PARAMETER EndFunction
|
|
Sets the message to "End [FunctionName] log.", where FunctionName is the name of the calling function, and adds it to the log variable.
|
|
.PARAMETER OutputPath
|
|
The file path for exporting the log to a CSV file when using the End switch.
|
|
.EXAMPLE
|
|
Write-AuditLog -Message "This is a test message."
|
|
|
|
Writes a test message with the default severity (Information) to the console and adds it to the log variable.
|
|
.EXAMPLE
|
|
Write-AuditLog -Message "This is a warning message." -Severity "Warning"
|
|
|
|
Writes a warning message to the console and adds it to the log variable.
|
|
.EXAMPLE
|
|
Write-AuditLog -Start
|
|
|
|
Initializes the log variable and sets the message to "Begin [FunctionName] Log.", where FunctionName is the name of the calling function.
|
|
.EXAMPLE
|
|
Write-AuditLog -BeginFunction
|
|
|
|
Sets the message to "Begin [FunctionName] function log.", where FunctionName is the name of the calling function, and adds it to the log variable.
|
|
.EXAMPLE
|
|
Write-AuditLog -EndFunction
|
|
|
|
Sets the message to "End [FunctionName] log.", where FunctionName is the name of the calling function, and adds it to the log variable.
|
|
.EXAMPLE
|
|
Write-AuditLog -End -OutputPath "C:\Logs\auditlog.csv"
|
|
|
|
Sets the message to "End Log", adds it to the log variable, and exports the log to a CSV file.
|
|
.NOTES
|
|
Author: DrIOSx
|
|
#>
|
|
[CmdletBinding(DefaultParameterSetName = 'Default')]
|
|
param(
|
|
###
|
|
[Parameter(
|
|
Mandatory = $false,
|
|
HelpMessage = 'Input a Message string.',
|
|
Position = 0,
|
|
ParameterSetName = 'Default',
|
|
ValueFromPipeline = $true
|
|
)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[string]$Message,
|
|
###
|
|
[Parameter(
|
|
Mandatory = $false,
|
|
HelpMessage = 'Information, Warning or Error.',
|
|
Position = 1,
|
|
ParameterSetName = 'Default',
|
|
ValueFromPipelineByPropertyName = $true
|
|
)]
|
|
[ValidateNotNullOrEmpty()]
|
|
[ValidateSet('Information', 'Warning', 'Error')]
|
|
[string]$Severity = 'Information',
|
|
###
|
|
[Parameter(
|
|
Mandatory = $false,
|
|
ParameterSetName = 'End'
|
|
)]
|
|
[switch]$End,
|
|
###
|
|
[Parameter(
|
|
Mandatory = $false,
|
|
ParameterSetName = 'BeginFunction'
|
|
)]
|
|
[switch]$BeginFunction,
|
|
[Parameter(
|
|
Mandatory = $false,
|
|
ParameterSetName = 'EndFunction'
|
|
)]
|
|
[switch]$EndFunction,
|
|
###
|
|
[Parameter(
|
|
Mandatory = $false,
|
|
ParameterSetName = 'Start'
|
|
)]
|
|
[switch]$Start,
|
|
###
|
|
[Parameter(
|
|
Mandatory = $false,
|
|
ParameterSetName = 'End'
|
|
)]
|
|
[string]$OutputPath
|
|
)
|
|
begin {
|
|
$ErrorActionPreference = "SilentlyContinue"
|
|
# Define variables to hold information about the command that was invoked.
|
|
$ModuleName = $Script:MyInvocation.MyCommand.Name -replace '\..*'
|
|
$callStack = Get-PSCallStack
|
|
if ($callStack.Count -gt 1) {
|
|
$FuncName = $callStack[1].Command
|
|
} else {
|
|
$FuncName = "DirectCall" # Or any other default name you prefer
|
|
}
|
|
#Write-Verbose "Funcname Name is $FuncName!" -Verbose
|
|
$ModuleVer = $MyInvocation.MyCommand.Version.ToString()
|
|
# Set the error action preference to continue.
|
|
$ErrorActionPreference = "Continue"
|
|
}
|
|
process {
|
|
try {
|
|
if (-not $Start -and -not (Test-Path variable:script:LogString)) {
|
|
throw "The logging variable is not initialized. Please call Write-AuditLog with the -Start switch or ensure $script:LogString is set."
|
|
}
|
|
$Function = $($FuncName + '.v' + $ModuleVer)
|
|
if ($Start) {
|
|
$script:LogString = @()
|
|
$Message = '+++ Begin Log | ' + $Function + ' |'
|
|
}
|
|
elseif ($BeginFunction) {
|
|
$Message = '>>> Begin Function Log | ' + $Function + ' |'
|
|
}
|
|
$logEntry = [pscustomobject]@{
|
|
Time = ((Get-Date).ToString('yyyy-MM-dd hh:mmTss'))
|
|
Module = $ModuleName
|
|
PSVersion = ($PSVersionTable.PSVersion).ToString()
|
|
PSEdition = ($PSVersionTable.PSEdition).ToString()
|
|
IsAdmin = $(Test-IsAdmin)
|
|
User = "$Env:USERDOMAIN\$Env:USERNAME"
|
|
HostName = $Env:COMPUTERNAME
|
|
InvokedBy = $Function
|
|
Severity = $Severity
|
|
Message = $Message
|
|
RunID = -1
|
|
}
|
|
if ($BeginFunction) {
|
|
$maxRunID = ($script:LogString | Where-Object { $_.InvokedBy -eq $Function } | Measure-Object -Property RunID -Maximum).Maximum
|
|
if ($null -eq $maxRunID) { $maxRunID = -1 }
|
|
$logEntry.RunID = $maxRunID + 1
|
|
}
|
|
else {
|
|
$lastRunID = ($script:LogString | Where-Object { $_.InvokedBy -eq $Function } | Select-Object -Last 1).RunID
|
|
if ($null -eq $lastRunID) { $lastRunID = 0 }
|
|
$logEntry.RunID = $lastRunID
|
|
}
|
|
if ($EndFunction) {
|
|
$FunctionStart = "$((($script:LogString | Where-Object {$_.InvokedBy -eq $Function -and $_.RunId -eq $lastRunID } | Sort-Object Time)[0]).Time)"
|
|
$startTime = ([DateTime]::ParseExact("$FunctionStart", 'yyyy-MM-dd hh:mmTss', $null))
|
|
$endTime = Get-Date
|
|
$timeTaken = $endTime - $startTime
|
|
$Message = '<<< End Function Log | ' + $Function + ' | Runtime: ' + "$($timeTaken.Minutes) min $($timeTaken.Seconds) sec"
|
|
$logEntry.Message = $Message
|
|
}
|
|
elseif ($End) {
|
|
$startTime = ([DateTime]::ParseExact($($script:LogString[0].Time), 'yyyy-MM-dd hh:mmTss', $null))
|
|
$endTime = Get-Date
|
|
$timeTaken = $endTime - $startTime
|
|
$Message = '--- End Log | ' + $Function + ' | Runtime: ' + "$($timeTaken.Minutes) min $($timeTaken.Seconds) sec"
|
|
$logEntry.Message = $Message
|
|
}
|
|
$script:LogString += $logEntry
|
|
switch ($Severity) {
|
|
'Warning' {
|
|
Write-Warning ('[WARNING] ! ' + $Message)
|
|
$UserInput = Read-Host "Warning encountered! Do you want to continue? (Y/N)"
|
|
if ($UserInput -eq 'N') {
|
|
throw "Script execution stopped by user."
|
|
}
|
|
}
|
|
'Error' { Write-Error ('[ERROR] X - ' + $FuncName + ' ' + $Message) -ErrorAction Continue }
|
|
'Verbose' { Write-Verbose ('[VERBOSE] ~ ' + $Message) }
|
|
Default { Write-Information ('[INFO] * ' + $Message) -InformationAction Continue}
|
|
}
|
|
}
|
|
catch {
|
|
throw "Write-AuditLog encountered an error (process block): $($_)"
|
|
}
|
|
|
|
}
|
|
end {
|
|
try {
|
|
if ($End) {
|
|
if (-not [string]::IsNullOrEmpty($OutputPath)) {
|
|
$script:LogString | Export-Csv -Path $OutputPath -NoTypeInformation
|
|
Write-Verbose "LogPath: $(Split-Path -Path $OutputPath -Parent)"
|
|
}
|
|
else {
|
|
throw "OutputPath is not specified for End action."
|
|
}
|
|
}
|
|
}
|
|
catch {
|
|
throw "Error in Write-AuditLog (end block): $($_.Exception.Message)"
|
|
}
|
|
}
|
|
} |