Private/Write-Debug.ps1
function Write-ACMEDebug{ [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Justification = 'Currently using Write-Host because it supports -NoNewLine')] [Diagnostics.CodeAnalysis.SuppressMessageAttribute('InjectionRisk.StaticPropertyInjection', '', Justification = 'No concern with dynamic member access here -- this is being flagged due to our reading of the function return object ($fro) to enumerate properties containing object arrays on/around line 39')] [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string] $callingFunction, [Parameter(Mandatory = $true)] $fro, [Parameter(Mandatory = $true)] [Boolean] $functionSucceeded, [Parameter(Mandatory = $false)] [string] $debugMode = $DEFAULT_DEBUG_MODE, [Parameter(Mandatory = $false)] [string] $debugLogDirectory = $DEFAULT_DEBUG_LOG_DIRECTORY ) # check to ensure that the debugMode is an expected value # ordinarilyt, this would be caught by the parameter definition in each function (though the use of the ValidateScript attribute) # However, if the -debugMode parameter is not specified, the ValidateScript is not used. This means that if the user # set a default value for this parameter (either via the .psm1 file or a system environment value), they could have a bad/unexpected value if($debugMode -notin ('EVT', 'File', 'Both')){ Write-Host "[[ DEBUG WARNING: debugMode parameter is not an expected value! We expect it to be 'EVT', 'File', or 'Both', but the value is '$debugMode'.`nThis may have happened if the default value was incorrectly set in the module's .psm1 file or the CERTIFICAT_DEFAULT_DEBUG_MODE system environment variable.`nDebug logging will NOT occur!]]" -ForegroundColor Red -BackgroundColor Black return } # build the message to be logged $logMessage = "[ CertifiCat-ps Debug Message ]`n" $logMessage += "Function: $callingFunction `n" $logMessage += "Completed: $(Get-Date)`n" if($null -ne $env:userdomain){ $logMessage += "Running As User: $($env:userdomain)\$($env:USERNAME)`n" } else { $logMessage += "Running As User: $($env:USERNAME)`n" } $logMessage += "Function Return Object:`n" # attempt to pretty-print the function return object into something slightly more readable $fro | Get-Member | where-object {$_.MemberType -eq "NoteProperty"} | foreach-object { $propType = ($_.Definition -split "\s")[0] # check to see what type of property this is -- we only want to expand object arrays if($_.Definition -match 'Object\[\]'){ # Some objects may just be a simple array list, while others may be an array of key-value pairs, so we need to account for both if($null -eq $fro.($_.Name).Keys){ # This is a simple array list -- make sure it's not null if(($fro.($_.Name).Length -lt 1)){ $logMessage += "`t-> Property '$($_.Name)' is an object whose contents are null`n" } else { $logMessage += "`t-> Property '$($_.Name)' is an object and with the following contents:`n" $_ | foreach-object{ $logMessage += "`t`t->$($fro.($_.Name))`n" } } } else { # This is an array with key/value pairs, so let's enumerate it $logMessage += "`t-> Property '$($_.Name)' is an object of type '$propType' and with the following properties:`n" foreach($prop in $($fro.($_.Name))){ $logMessage += "`t`t$($prop.Keys): $($prop.Values)`n" } } } else { $logMessage += "`t-> Property '$($_.Name)' is of type '$propType' and has value: $($fro.($_.Name))`n" } } $logMessage += "--------------------------------------------------------------`n" # check to see if we're logging to a file if(($debugMode -eq "file") -or ($debugMode -eq "both")){ # make sure that the directory exists if(-not (Test-Path $debugLogDirectory)){ New-Item -ItemType Directory -Path $debugLogDirectory | Out-Null } $logMessage | Out-File "$debugLogDirectory\certificat-debug-$(get-date -format "MM-dd-yyyy").log" -Append } # check to see if we're logging to the event log if(($debugMode -eq "EVT") -or ($debugMode -eq "both")){ # make sure we have admin access -- needed to interact with the event log if(!(Assert-AdminAccess -hideOutput)) { # we don't -- check to see if we have a log file path we can fall back to if(($null -ne $debugLogDirectory) -or ($debugLogDirectory -ne "")){ Write-Host "[[ DEBUG WARNING: debugMode parameter specified logging to the Windows Event Log, however, we don't have administrative access. Debug data WILL NOT be written to the event log! ]]" -ForegroundColor Red -BackgroundColor Black } } else { # check to see if the event log source we want exists if( -not [System.Diagnostics.EventLog]::SourceExists($DEFAULT_EVENT_LOG_SOURCE)){ # create it [System.Diagnostics.EventLog]::CreateEventSource($DEFAULT_EVENT_LOG_SOURCE, "Application") } # determind the log level if($functionSucceeded){ $logLevel = "Information" } else { $logLevel = "Error" } # get the event id we care about $eventID = Get-DebugEventID $callingFunction $functionSucceeded # make sure that we have an event id if($null -ne $eventID){ # write the log [System.Diagnostics.EventLog]::WriteEntry($DEFAULT_EVENT_LOG_SOURCE, $logMessage, $logLevel, $eventId) } else { Write-Host "[[ DEBUG WARNING: debugMode parameter specified logging to the Windows Event Log, however, we couldn't find an event ID associated with function '$callingFunction' and functionSucceeded = '$functionSucceeded'. Debug data WILL NOT be written to the event log! ]]" -ForegroundColor Red -BackgroundColor Black } } } } |