polybius01

Write-Log

Apr 13th, 2026
28
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.51 KB | None | 0 0
  1. Function Write-Log {
  2. <#
  3. .SYNOPSIS
  4. Write messages to a log file in CMTrace.exe compatible format or Legacy text file format.
  5. .DESCRIPTION
  6. Write messages to a log file in CMTrace.exe compatible format or Legacy text file format and optionally display in the console.
  7. .PARAMETER Message
  8. The message to write to the log file or output to the console.
  9. .PARAMETER Severity
  10. Defines message type. When writing to console or CMTrace.exe log format, it allows highlighting of message type.
  11. Options: 1 = Information (default), 2 = Warning (highlighted in yellow), 3 = Error (highlighted in red)
  12. .PARAMETER Source
  13. The source of the message being logged.
  14. .PARAMETER ScriptSection
  15. The heading for the portion of the script that is being executed. Default is: $script:installPhase.
  16. .PARAMETER LogType
  17. Choose whether to write a CMTrace.exe compatible log file or a Legacy text log file.
  18. .PARAMETER LogFileDirectory
  19. Set the directory where the log file will be saved.
  20. .PARAMETER LogFileName
  21. Set the name of the log file.
  22. .PARAMETER MaxLogFileSizeMB
  23. Maximum file size limit for log file in megabytes (MB). Default is 10 MB.
  24. .PARAMETER WriteHost
  25. Write the log message to the console.
  26. .PARAMETER ContinueOnError
  27. Suppress writing log message to console on failure to write message to log file. Default is: $true.
  28. .PARAMETER PassThru
  29. Return the message that was passed to the function
  30. .PARAMETER DebugMessage
  31. Specifies that the message is a debug message. Debug messages only get logged if -LogDebugMessage is set to $true.
  32. .PARAMETER LogDebugMessage
  33. Debug messages only get logged if this parameter is set to $true in the config XML file.
  34. .EXAMPLE
  35. Write-Log -Message "Installing patch MS15-031" -Source 'Add-Patch' -LogType 'CMTrace'
  36. .EXAMPLE
  37. Write-Log -Message "Script is running on Windows 8" -Source 'Test-ValidOS' -LogType 'Legacy'
  38. .NOTES
  39. .LINK
  40. http://psappdeploytoolkit.com
  41. #>
  42. [CmdletBinding()]
  43. Param (
  44. [Parameter(Mandatory=$true,Position=0,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
  45. [AllowEmptyCollection()]
  46. [Alias('Text')]
  47. [string[]]$Message,
  48. [Parameter(Mandatory=$false,Position=1)]
  49. [ValidateRange(1,3)]
  50. [int16]$Severity = 1,
  51. [Parameter(Mandatory=$false,Position=2)]
  52. [ValidateNotNull()]
  53. [string]$Source = '',
  54. [Parameter(Mandatory=$false,Position=3)]
  55. [ValidateNotNullorEmpty()]
  56. [string]$ScriptSection = $script:installPhase,
  57. [Parameter(Mandatory=$false,Position=4)]
  58. [ValidateSet('CMTrace','Legacy')]
  59. [string]$LogType = $configToolkitLogStyle,
  60. [Parameter(Mandatory=$false,Position=5)]
  61. [ValidateNotNullorEmpty()]
  62. [string]$LogFileDirectory = $(If ($configToolkitCompressLogs) { $logTempFolder } Else { $configToolkitLogDir }),
  63. [Parameter(Mandatory=$false,Position=6)]
  64. [ValidateNotNullorEmpty()]
  65. [string]$LogFileName = $logName,
  66. [Parameter(Mandatory=$false,Position=7)]
  67. [ValidateNotNullorEmpty()]
  68. [decimal]$MaxLogFileSizeMB = $configToolkitLogMaxSize,
  69. [Parameter(Mandatory=$false,Position=8)]
  70. [ValidateNotNullorEmpty()]
  71. [boolean]$WriteHost = $configToolkitLogWriteToHost,
  72. [Parameter(Mandatory=$false,Position=9)]
  73. [ValidateNotNullorEmpty()]
  74. [boolean]$ContinueOnError = $true,
  75. [Parameter(Mandatory=$false,Position=10)]
  76. [switch]$PassThru = $false,
  77. [Parameter(Mandatory=$false,Position=11)]
  78. [switch]$DebugMessage = $false,
  79. [Parameter(Mandatory=$false,Position=12)]
  80. [boolean]$LogDebugMessage = $configToolkitLogDebugMessage
  81. )
  82.  
  83. Begin {
  84. ## Get the name of this function
  85. [string]${CmdletName} = $PSCmdlet.MyInvocation.MyCommand.Name
  86.  
  87. ## Logging Variables
  88. # Log file date/time
  89. [string]$LogTime = (Get-Date -Format 'HH\:mm\:ss.fff').ToString()
  90. [string]$LogDate = (Get-Date -Format 'MM-dd-yyyy').ToString()
  91. If (-not (Test-Path -LiteralPath 'variable:LogTimeZoneBias')) { [int32]$script:LogTimeZoneBias = [timezone]::CurrentTimeZone.GetUtcOffset([datetime]::Now).TotalMinutes }
  92. [string]$LogTimePlusBias = $LogTime + $script:LogTimeZoneBias
  93. # Initialize variables
  94. [boolean]$ExitLoggingFunction = $false
  95. If (-not (Test-Path -LiteralPath 'variable:DisableLogging')) { $DisableLogging = $false }
  96. # Check if the script section is defined
  97. [boolean]$ScriptSectionDefined = [boolean](-not [string]::IsNullOrEmpty($ScriptSection))
  98. # Get the file name of the source script
  99. Try {
  100. If ($script:MyInvocation.Value.ScriptName) {
  101. [string]$ScriptSource = Split-Path -Path $script:MyInvocation.Value.ScriptName -Leaf -ErrorAction 'Stop'
  102. }
  103. Else {
  104. [string]$ScriptSource = Split-Path -Path $script:MyInvocation.MyCommand.Definition -Leaf -ErrorAction 'Stop'
  105. }
  106. }
  107. Catch {
  108. $ScriptSource = ''
  109. }
  110.  
  111. ## Create script block for generating CMTrace.exe compatible log entry
  112. [scriptblock]$CMTraceLogString = {
  113. Param (
  114. [string]$lMessage,
  115. [string]$lSource,
  116. [int16]$lSeverity
  117. )
  118. "<![LOG[$lMessage]LOG]!>" + "<time=`"$LogTimePlusBias`" " + "date=`"$LogDate`" " + "component=`"$lSource`" " + "context=`"$([Security.Principal.WindowsIdentity]::GetCurrent().Name)`" " + "type=`"$lSeverity`" " + "thread=`"$PID`" " + "file=`"$ScriptSource`">"
  119. }
  120.  
  121. ## Create script block for writing log entry to the console
  122. [scriptblock]$WriteLogLineToHost = {
  123. Param (
  124. [string]$lTextLogLine,
  125. [int16]$lSeverity
  126. )
  127. If ($WriteHost) {
  128. # Only output using color options if running in a host which supports colors.
  129. If ($Host.UI.RawUI.ForegroundColor) {
  130. Switch ($lSeverity) {
  131. 3 { Write-Host -Object $lTextLogLine -ForegroundColor 'Red' -BackgroundColor 'Black' }
  132. 2 { Write-Host -Object $lTextLogLine -ForegroundColor 'Yellow' -BackgroundColor 'Black' }
  133. 1 { Write-Host -Object $lTextLogLine }
  134. }
  135. }
  136. # If executing "powershell.exe -File <filename>.ps1 > log.txt", then all the Write-Host calls are converted to Write-Output calls so that they are included in the text log.
  137. Else {
  138. Write-Output -InputObject $lTextLogLine
  139. }
  140. }
  141. }
  142.  
  143. ## Exit function if it is a debug message and logging debug messages is not enabled in the config XML file
  144. If (($DebugMessage) -and (-not $LogDebugMessage)) { [boolean]$ExitLoggingFunction = $true; Return }
  145. ## Exit function if logging to file is disabled and logging to console host is disabled
  146. If (($DisableLogging) -and (-not $WriteHost)) { [boolean]$ExitLoggingFunction = $true; Return }
  147. ## Exit Begin block if logging is disabled
  148. If ($DisableLogging) { Return }
  149. ## Exit function function if it is an [Initialization] message and the toolkit has been relaunched
  150. If (($AsyncToolkitLaunch) -and ($ScriptSection -eq 'Initialization')) { [boolean]$ExitLoggingFunction = $true; Return }
  151.  
  152. ## Create the directory where the log file will be saved
  153. If (-not (Test-Path -LiteralPath $LogFileDirectory -PathType 'Container')) {
  154. Try {
  155. $null = New-Item -Path $LogFileDirectory -Type 'Directory' -Force -ErrorAction 'Stop'
  156. }
  157. Catch {
  158. [boolean]$ExitLoggingFunction = $true
  159. # If error creating directory, write message to console
  160. If (-not $ContinueOnError) {
  161. Write-Host -Object "[$LogDate $LogTime] [${CmdletName}] $ScriptSection :: Failed to create the log directory [$LogFileDirectory]. `n$(Resolve-Error)" -ForegroundColor 'Red'
  162. }
  163. Return
  164. }
  165. }
  166.  
  167. ## Assemble the fully qualified path to the log file
  168. [string]$LogFilePath = Join-Path -Path $LogFileDirectory -ChildPath $LogFileName
  169. }
  170. Process {
  171. ## Exit function if logging is disabled
  172. If ($ExitLoggingFunction) { Return }
  173.  
  174. ForEach ($Msg in $Message) {
  175. ## If the message is not $null or empty, create the log entry for the different logging methods
  176. [string]$CMTraceMsg = ''
  177. [string]$ConsoleLogLine = ''
  178. [string]$LegacyTextLogLine = ''
  179. If ($Msg) {
  180. # Create the CMTrace log message
  181. If ($ScriptSectionDefined) { [string]$CMTraceMsg = "[$ScriptSection] :: $Msg" }
  182.  
  183. # Create a Console and Legacy "text" log entry
  184. [string]$LegacyMsg = "[$LogDate $LogTime]"
  185. If ($ScriptSectionDefined) { [string]$LegacyMsg += " [$ScriptSection]" }
  186. If ($Source) {
  187. [string]$ConsoleLogLine = "$LegacyMsg [$Source] :: $Msg"
  188. Switch ($Severity) {
  189. 3 { [string]$LegacyTextLogLine = "$LegacyMsg [$Source] [Error] :: $Msg" }
  190. 2 { [string]$LegacyTextLogLine = "$LegacyMsg [$Source] [Warning] :: $Msg" }
  191. 1 { [string]$LegacyTextLogLine = "$LegacyMsg [$Source] [Info] :: $Msg" }
  192. }
  193. }
  194. Else {
  195. [string]$ConsoleLogLine = "$LegacyMsg :: $Msg"
  196. Switch ($Severity) {
  197. 3 { [string]$LegacyTextLogLine = "$LegacyMsg [Error] :: $Msg" }
  198. 2 { [string]$LegacyTextLogLine = "$LegacyMsg [Warning] :: $Msg" }
  199. 1 { [string]$LegacyTextLogLine = "$LegacyMsg [Info] :: $Msg" }
  200. }
  201. }
  202. }
  203.  
  204. ## Execute script block to create the CMTrace.exe compatible log entry
  205. [string]$CMTraceLogLine = & $CMTraceLogString -lMessage $CMTraceMsg -lSource $Source -lSeverity $Severity
  206.  
  207. ## Choose which log type to write to file
  208. If ($LogType -ieq 'CMTrace') {
  209. [string]$LogLine = $CMTraceLogLine
  210. }
  211. Else {
  212. [string]$LogLine = $LegacyTextLogLine
  213. }
  214.  
  215. ## Write the log entry to the log file if logging is not currently disabled
  216. If (-not $DisableLogging) {
  217. Try {
  218. $LogLine | Out-File -FilePath $LogFilePath -Append -NoClobber -Force -Encoding 'UTF8' -ErrorAction 'Stop'
  219. }
  220. Catch {
  221. If (-not $ContinueOnError) {
  222. Write-Host -Object "[$LogDate $LogTime] [$ScriptSection] [${CmdletName}] :: Failed to write message [$Msg] to the log file [$LogFilePath]. `n$(Resolve-Error)" -ForegroundColor 'Red'
  223. }
  224. }
  225. }
  226.  
  227. ## Execute script block to write the log entry to the console if $WriteHost is $true
  228. & $WriteLogLineToHost -lTextLogLine $ConsoleLogLine -lSeverity $Severity
  229. }
  230. }
  231. End {
  232. ## Archive log file if size is greater than $MaxLogFileSizeMB and $MaxLogFileSizeMB > 0
  233. Try {
  234. If ((-not $ExitLoggingFunction) -and (-not $DisableLogging)) {
  235. [IO.FileInfo]$LogFile = Get-ChildItem -LiteralPath $LogFilePath -ErrorAction 'Stop'
  236. [decimal]$LogFileSizeMB = $LogFile.Length/1MB
  237. If (($LogFileSizeMB -gt $MaxLogFileSizeMB) -and ($MaxLogFileSizeMB -gt 0)) {
  238. ## Change the file extension to "lo_"
  239. [string]$ArchivedOutLogFile = [IO.Path]::ChangeExtension($LogFilePath, 'lo_')
  240. [hashtable]$ArchiveLogParams = @{ ScriptSection = $ScriptSection; Source = ${CmdletName}; Severity = 2; LogFileDirectory = $LogFileDirectory; LogFileName = $LogFileName; LogType = $LogType; MaxLogFileSizeMB = 0; WriteHost = $WriteHost; ContinueOnError = $ContinueOnError; PassThru = $false }
  241.  
  242. ## Log message about archiving the log file
  243. $ArchiveLogMessage = "Maximum log file size [$MaxLogFileSizeMB MB] reached. Rename log file to [$ArchivedOutLogFile]."
  244. Write-Log -Message $ArchiveLogMessage @ArchiveLogParams
  245.  
  246. ## Archive existing log file from <filename>.log to <filename>.lo_. Overwrites any existing <filename>.lo_ file. This is the same method SCCM uses for log files.
  247. Move-Item -LiteralPath $LogFilePath -Destination $ArchivedOutLogFile -Force -ErrorAction 'Stop'
  248.  
  249. ## Start new log file and Log message about archiving the old log file
  250. $NewLogMessage = "Previous log file was renamed to [$ArchivedOutLogFile] because maximum log file size of [$MaxLogFileSizeMB MB] was reached."
  251. Write-Log -Message $NewLogMessage @ArchiveLogParams
  252. }
  253. }
  254. }
  255. Catch {
  256. ## If renaming of file fails, script will continue writing to log file even if size goes over the max file size
  257. }
  258. Finally {
  259. If ($PassThru) { Write-Output -InputObject $Message }
  260. }
  261. }
  262. }
  263. #endregion
Tags: PSDeployApp
Advertisement
Add Comment
Please, Sign In to add comment