add: Logging functions for future use
This commit is contained in:
22
source/Private/Test-IsAdmin.ps1
Normal file
22
source/Private/Test-IsAdmin.ps1
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
function Test-IsAdmin {
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Checks if the current user is an administrator on the machine.
|
||||||
|
.DESCRIPTION
|
||||||
|
This private function returns a Boolean value indicating whether
|
||||||
|
the current user has administrator privileges on the machine.
|
||||||
|
It does this by creating a new WindowsPrincipal object, passing
|
||||||
|
in a WindowsIdentity object representing the current user, and
|
||||||
|
then checking if that principal is in the Administrator role.
|
||||||
|
.INPUTS
|
||||||
|
None.
|
||||||
|
.OUTPUTS
|
||||||
|
Boolean. Returns True if the current user is an administrator, and False otherwise.
|
||||||
|
.EXAMPLE
|
||||||
|
PS C:\> Test-IsAdmin
|
||||||
|
True
|
||||||
|
#>
|
||||||
|
|
||||||
|
# Create a new WindowsPrincipal object for the current user and check if it is in the Administrator role
|
||||||
|
(New-Object Security.Principal.WindowsPrincipal ([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
|
||||||
|
}
|
212
source/Private/Write-AuditLog.ps1
Normal file
212
source/Private/Write-AuditLog.ps1
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
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)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
27
tests/Unit/Private/Test-IsAdmin.tests.ps1
Normal file
27
tests/Unit/Private/Test-IsAdmin.tests.ps1
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path
|
||||||
|
$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{
|
||||||
|
($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and
|
||||||
|
$(try { Test-ModuleManifest $_.FullName -ErrorAction Stop } catch { $false } )
|
||||||
|
}).BaseName
|
||||||
|
|
||||||
|
|
||||||
|
Import-Module $ProjectName
|
||||||
|
|
||||||
|
InModuleScope $ProjectName {
|
||||||
|
Describe Get-PrivateFunction {
|
||||||
|
Context 'Default' {
|
||||||
|
BeforeEach {
|
||||||
|
$return = Get-PrivateFunction -PrivateData 'string'
|
||||||
|
}
|
||||||
|
|
||||||
|
It 'Returns a single object' {
|
||||||
|
($return | Measure-Object).Count | Should -Be 1
|
||||||
|
}
|
||||||
|
|
||||||
|
It 'Returns a string based on the parameter PrivateData' {
|
||||||
|
$return | Should -Be 'string'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
27
tests/Unit/Private/Write-AuditLog.tests.ps1
Normal file
27
tests/Unit/Private/Write-AuditLog.tests.ps1
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
$ProjectPath = "$PSScriptRoot\..\..\.." | Convert-Path
|
||||||
|
$ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{
|
||||||
|
($_.Directory.Name -match 'source|src' -or $_.Directory.Name -eq $_.BaseName) -and
|
||||||
|
$(try { Test-ModuleManifest $_.FullName -ErrorAction Stop } catch { $false } )
|
||||||
|
}).BaseName
|
||||||
|
|
||||||
|
|
||||||
|
Import-Module $ProjectName
|
||||||
|
|
||||||
|
InModuleScope $ProjectName {
|
||||||
|
Describe Get-PrivateFunction {
|
||||||
|
Context 'Default' {
|
||||||
|
BeforeEach {
|
||||||
|
$return = Get-PrivateFunction -PrivateData 'string'
|
||||||
|
}
|
||||||
|
|
||||||
|
It 'Returns a single object' {
|
||||||
|
($return | Measure-Object).Count | Should -Be 1
|
||||||
|
}
|
||||||
|
|
||||||
|
It 'Returns a string based on the parameter PrivateData' {
|
||||||
|
$return | Should -Be 'string'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Reference in New Issue
Block a user