PoshCode Logo PowerShell Code Repository

Logger.psm1 0.4 by Joel Bennett 7 years ago (modification of post by Joel Bennett view diff)
View followups from Joel Bennett and Chris Feilen | diff | embed code: <script type="text/javascript" src="http://PoshCode.org/embed/1752"></script>download | new post

The simplest logger. In your script just import-module Logger and debug, verbose, warnings and errors are logged to file.

This is a simple wrapper around Log4Net which (by default) causes Write-Verbose, Write-Warning, Write-Debug, and Write-Error to log their output when called from (any) script. By default it logs to file, but it can log to the event log, console, .net trace or debug, udp, xml, etc by simply using the Get-Logger function to configure new loggers (help is next)

There are a few extra helper methods in here, including Push-Context/Pop-Context (which you can call in your functions to enable stack tracing), and still more to come.

New in this release:

  1. <#
  2.    Name     : Universal Log4Net Logging Module (Logger.psm1)
  3.    Version  : 0.3
  4.    Author   : Joel Bennett (MVP)
  5.    Site     : http://www.HuddledMasses.org/
  6.  
  7.    Version History:
  8.    0.4 - Bugfix, Viewer and Documentation release.
  9.          Fixed a few typo-bugs
  10.          Added documentation (man page) comments for Get-Logger.
  11.          Changed a few parameter names (sorry) to make the default parameters more unique (so you have to type less on the command-line)
  12.          Changed the default logger to use the logger module's folder as a backup
  13.             (Some people might not have the Profile path -- this module could be installed anywhere and loaded by file name)
  14.          Fixed up the xml output with a nice stylesheet http`://poshcode.org/1750 that formats and makes the page refresh.
  15.    
  16.    0.3 - Cleanupable release.
  17.          Added Udp, Email,  Xml and RollingXml, as well as a "Chainsaw":http`://logging.apache.org/log4j/docs/chainsaw.html logger based on "Szymon Kobalczyk's configuration":http`://geekswithblogs.net/kobush/archive/2005/07/15/46627.aspx.
  18.          Note: there is a "KNOWN BUG with Log4Net UDP":http`://odalet.wordpress.com/2007/01/13/log4net-ip-parsing-bug-when-used-with-framework-net-20/ which can be patched, but hasn't been released.
  19.          Added a Close-Logger method to clean up the Xml logger
  20.          NOTE: the Rolling XML Logger produces invalid XML, and the XML logger only produces valid xml after it's been closed...
  21.                I did contribute an "XSLT stylesheet for Log4Net":http`://poshcode.org/1746 which you could use as well
  22.          
  23.    0.2 - Configless release.
  24.          Now configures with inline XML, and supports switches to create "reasonable" default loggers
  25.          Changed all the functions to Write-*Log so they don't overwrite the cmdlets
  26.          Added -Logger parameter to take the name of the logger to use (it must be created beforehand via Get-Logger)
  27.          Created aliases for Write-* to override the cmdlets -- these are easy for users to remove without breaking the module
  28.          ** NEED to write some docs, but basically, this is stupid simple to use, just:
  29.             Import-Module Logger
  30.             Write-Verbose "This message will be saved in your profile folder in a file named PowerShellLogger.log (by default)"
  31.          To change the defaults for your system, edit the last line in the module!!
  32.    0.1 - Initial release. http`://poshcode.org/1744 (Required config: http`://poshcode.org/1743)
  33.  
  34.    Uses Log4Net : http`://logging.apache.org/log4net/download.html
  35.    Documentation: http`://logging.apache.org/log4net/release/sdk/
  36.    
  37.    NOTES:
  38.    By default, this overwrites the Write-* cmdlets for Error, Warning, Debug, Verbose, and even Host.
  39.    This means that you may end up logging a lot of stuff you didn't intend to log (ie: verbose output from other scripts)
  40.    
  41.    To avoid this behavior, remove the aliases after importing it
  42.    Import-Module Logger; Remove-Item Alias:Write-*
  43.    Write-Warning "This is your warning"
  44.    Write-Debug   "You should know that..."
  45.    Write-Verbose "Everything would be logged, otherwise"
  46.  
  47.    ***** NOTE: IT ONLY OVERRIDES THE DEFAULTS FOR SCRIPTS *****
  48.    It currently has no effect on error/verbose/warning that is logged from cmdlets.
  49.    
  50. #>
  51.  
  52. Add-Type -Path $PSScriptRoot\log4net.dll
  53.  
  54. function Get-RelativePath {
  55. <#
  56. .SYNOPSIS
  57.    Get a path to a file (or folder) relative to another folder
  58. .DESCRIPTION
  59.    Converts the FilePath to a relative path rooted in the specified Folder
  60. .PARAMETER Folder
  61.    The folder to build a relative path from
  62. .PARAMETER FilePath
  63.    The File (or folder) to build a relative path TO
  64. .PARAMETER Resolve
  65.    If true, the file and folder paths must exist
  66. .Example
  67.    Get-RelativePath ~\Documents\WindowsPowerShell\Logs\ ~\Documents\WindowsPowershell\Modules\Logger\log4net.xslt
  68.    
  69.    ..\Modules\Logger\log4net.xslt
  70.    
  71.    Returns a path to log4net.xslt relative to the Logs folder
  72. #>
  73. [CmdletBinding()]
  74. param(
  75.    [Parameter(Mandatory=$true, Position=0)]
  76.    [string]$Folder
  77. ,
  78.    [Parameter(Mandatory=$true, Position=1, ValueFromPipelineByPropertyName=$true)]
  79.    [Alias("FullName")]
  80.    [string]$FilePath
  81. ,
  82.    [switch]$Resolve
  83. )
  84. process {
  85.    $from = $Folder = split-path $Folder -NoQualifier -Resolve:$Resolve
  86.    $to = $filePath = split-path $filePath -NoQualifier -Resolve:$Resolve
  87.  
  88.    while($from -and $to -and ($from -ne $to)) {
  89.       if($from.Length -gt $to.Length) {
  90.          $from = split-path $from
  91.       } else {
  92.          $to = split-path $to
  93.       }
  94.    }
  95.  
  96.    $filepath = $filepath -replace "^"+[regex]::Escape($to)+"\\"
  97.    $from = $Folder
  98.    while($from -and $to -and $from -gt $to ) {
  99.       $from = split-path $from
  100.       $filepath = join-path ".." $filepath
  101.    }
  102.    Write-Output $filepath
  103. }
  104. }
  105.  
  106. function Get-Logger {
  107. <#
  108. .SYNOPSIS
  109.    Get an existing Logger by name, or create a new logger
  110. .DESCRIPTION
  111.    Returns a logger matching the name (wildcards allowed) provided.
  112.    
  113.    If the logger already exists, it is returned with it's settings as-is, unless the -Force switch is specified, in which case the new settings are used
  114.    
  115.    If only one logger matches the name, that logger becomes the new default logger.
  116.  
  117. .PARAMETER Name
  118.    The name of the logger to find or create. If no name is specified, all existing loggers are returned.
  119.  
  120. .PARAMETER Level
  121.    The level at which to log in this new logger. Defaults to "DEBUG"
  122.    Possible levels are as follows (each level includes all levels above it):
  123.    
  124.    FATAL
  125.    ERROR
  126.    WARN  (aka WARNING)
  127.    INFO  (aka VERBOSE, HOST)
  128.    DEBUG
  129.    
  130. .PARAMETER MessagePattern
  131.    The pattern for loggers which use patterns (mostly the file loggers). Defaults to:
  132.    "%date %-5level %logger [%property{NDC}] - %message%newline"
  133.    
  134.    For a complete list of possible pattern names, see:
  135.    http://logging.apache.org/log4net/release/sdk/log4net.Layout.PatternLayout.html
  136.    
  137. .PARAMETER Folder
  138.    The folder where log files are kept. Defaults to your Documents\WindowsPowerShell folder.
  139.    NOTE: if the specified folder does not exist, the fallback is your Documents\WindowsPowerShell folder,
  140.          but if that doesn't exist, the folder where this file is stored is used.
  141.  
  142. .PARAMETER EmailTo
  143.    An email address to send WARNING or above messages to. REQUIRES that your $PSEmailServer variable be set
  144. .PARAMETER Console
  145.    Creates a colored console logger
  146. .PARAMETER EventLog
  147.    Creates an EventLog logger
  148. .PARAMETER TraceLog
  149.    Creates a .Net Trace logger
  150. .PARAMETER DebugLog
  151.    Creates a .Net Debug logger
  152. .PARAMETER FileLog
  153.    Creates a file logger. Note the LogLock parameter!
  154. .PARAMETER RollingFileLog
  155.    Creates a rolling file logger with a max size of 250KB. Note the LogLock parameter!  
  156. .PARAMETER XmlLog
  157.    Creates an Xml-formatted file logger. Note the LogLock parameter!
  158.    
  159.    Note: the XmlLog will output an XML Header and will add a footer when the logger is closed.
  160.    This results in a log file which is readable in xml viewers like IE, particularly if you have a copy of the XSLT stylesheet for Log4Net (http://poshcode.org/1750) named log4net.xslt in the same folder with the log file.
  161.    
  162.    WARNING: Because of this, it does not APPEND to the file, but overwrites it each time you create the logger.
  163. .PARAMETER RollingXmlLog
  164.    Creates a rolling file Xml logger with a max size of 500KB. Note the LogLock parameter!
  165.    
  166.    Note: the rolling xml logger cannot create "valid" xml because it appends to the end of the file (and therefore can't guarantee the file is well-formed XML).
  167.    In order to get a valid Xml file, you can use a "*View.xml" file with contents like this (which this script will create):
  168.    
  169.    <?xml version="1.0" ?>
  170.    <?xml-stylesheet type="text/xsl" href="log4net.xslt"?>
  171.    <!DOCTYPE events [<!ENTITY data SYSTEM "PowerShellLogger.xml">]>
  172.    <log4net:events version="1.2" xmlns:log4net="http://logging.apache.org/log4net/schemas/log4net-events-1.2">
  173.       &data;
  174.    </log4net:events>
  175. .PARAMETER LogLock
  176.    Determines the type of file locking used (defaults to SHARED):
  177.    SHARED is the "MinimalLocking" model which opens the file once for each AcquireLock/ReleaseLock cycle, thus holding the lock for the minimal amount of time. This method of locking is considerably slower than...
  178.    
  179.    EXCLUSIVE is the "ExclusiveLocking" model which opens the file once for writing and holds it open until the logger is closed, maintaining an exclusive lock on the file the whole time..
  180. .PARAMETER UdpSend
  181.    Creates an UdpAppender which sends messages to the localmachine port 8080
  182.    We'll probably tweak this in a future release, but for now if you need to change that you need to edit the script
  183. .PARAMETER ChainsawSend
  184.    Like UdpSend, creates an UdpAppender which sends messages to the localmachine port 8080.
  185.    This logger uses the log4j xml formatter which is somewhat different than the default, and uses their namespace.  
  186. .PARAMETER Force
  187.    Force resetting the logger switches even if the logger already exists
  188. #>
  189. param(
  190.    [Parameter(Mandatory=$false, Position=0)]
  191.    [string]$Name = "*"
  192. ,
  193.    [Parameter(Mandatory=$false)]
  194.    [ValidateSet("DEBUG","INFO","WARN","ERROR","FATAL","VERBOSE","HOST","WARNING")]
  195.    [string]$Level = "DEBUG"
  196. ,
  197.    [Parameter(Mandatory=$false)]
  198.    $MessagePattern = "%date %-5level %logger [%property{NDC}] - %message%newline"
  199. ,
  200.    [Parameter(Mandatory=$false)]
  201.    [string]$Folder = $(Split-Path $Profile.CurrentUserAllHosts)
  202.    
  203. ,  [String]$EmailTo
  204. ,  [Switch]$Force
  205. ,  [Switch]$ConsoleLog
  206. ,  [Switch]$EventLog
  207. ,  [Switch]$TraceLog
  208. ,  [Switch]$DebugLog
  209. ,  [Switch]$FileLog
  210. ,  [Switch]$RollingFileLog
  211. ,  [Switch]$XmlLog
  212. ,  [Switch]$RollingXmlLog
  213. ,  [Switch]$UdpSend
  214. ,  [Switch]$ChainsawSend
  215. ,
  216.    [Parameter(Mandatory=$false, Position=99)]
  217.    [ValidateSet("Shared","Exclusive")]
  218.    [String]$LogLock = "Shared"
  219. )
  220.    ## Make sure the folder exists
  221.    if(!(Test-Path $Folder)) {
  222.       $Folder = Split-Path $Profile.CurrentUserAllHosts
  223.       if(!(Test-Path $Folder)) {
  224.          $Folder = $PSScriptRoot
  225.       }
  226.    }
  227.    
  228.    
  229.    Remove-Variable Loggers -EA 0
  230.    [log4net.LogManager]::GetCurrentLoggers() | Where-Object { $_.Logger.Name -Like $Name } | Tee-Object -Variable Loggers
  231.    if((!$Loggers -or $Force) -and !$Name.Contains('*')) {
  232.       if($Level -eq "VERBOSE") { $Level = "INFO" }
  233.       if($Level -eq "HOST")    { $Level = "INFO" }
  234.       if($Level -eq "WARNING") { $Level = "WARN" }
  235.  
  236.       $AppenderRefs = ''
  237.       if($Email)        {
  238.          if(!$PSEmailServer) { throw "You need to specify your SMTP mail server by setting the global $PSEmailServer variable" }
  239.          $AppenderRefs += "<appender-ref ref=""SmtpAppender"" />`n"
  240.          $Null,$Domain = $email -split "@",2
  241.       }
  242.      
  243.       if($LogLock -eq "Shared") {
  244.          $LockMode = "MinimalLock"
  245.       } else {
  246.          $LockMode = "ExclusiveLock"
  247.       }
  248.       $xslt = ""
  249.       if(Test-Path $PSScriptRoot\log4net.xslt) {
  250.          $xslt = @"
  251. <?xml-stylesheet type="text/xsl" href="$(Get-RelativePath $Folder $PSScriptRoot\log4net.xslt)"?>
  252. "@
  253.       }
  254.  
  255.  
  256.       if($EventLog)        { $AppenderRefs += "<appender-ref ref=""EventLogAppender"" />`n" }
  257.       if($TraceLog)        { $AppenderRefs += "<appender-ref ref=""TraceAppender"" />`n" }
  258.       if($DebugLog){ $AppenderRefs += "<appender-ref ref=""DebugAppender"" />`n" }
  259.       if($FileLog)         { $AppenderRefs += "<appender-ref ref=""FileAppender"" />`n" }
  260.       if($RollingFileLog)  { $AppenderRefs += "<appender-ref ref=""RollingFileAppender"" />`n" }
  261.       if($UdpSend)         { $AppenderRefs += "<appender-ref ref=""UdpAppender"" />`n" }
  262.       if($ChainsawSend)    { $AppenderRefs += "<appender-ref ref=""UdpLog4JAppender"" />`n" }
  263.       if($XmlLog)          { $AppenderRefs += "<appender-ref ref=""XmlAppender"" />`n" }
  264.       if($RollingXmlLog)   { $AppenderRefs += "<appender-ref ref=""RollingXmlAppender"" />`n"
  265.          if($VerbosePreference -gt "SilentlyContinue") { "Created XML viewer for you at: ${Folder}\${Name}View.Xml" }
  266.          Set-Content "${Folder}\${Name}View.Xml" @"
  267. <?xml version="1.0" ?>
  268. $xslt
  269. <!DOCTYPE events [<!ENTITY data SYSTEM "$Name.xml">]>
  270. <events version="1.2" xmlns:log4net="http`://logging.apache.org/log4net/schemas/log4net-events-1.2">
  271. <logname>$Name</logname>
  272.   &data;
  273. </events>
  274. "@      
  275.       }
  276.       $xslt = $xslt -replace "<","&lt;" -replace ">","&gt;" -replace '"',"'"
  277.      
  278.       if($ConsoleLog -or ($AppenderRefs.Length -eq 0)) { $AppenderRefs += "<appender-ref ref=""ColoredConsoleAppender"" />`n" }
  279.  
  280.       [log4net.LogManager]::GetLogger($Name) | Tee-Object -Variable Script:Logger | Where { $Loggers -notcontains $_ }
  281.      
  282.       [xml]$config = @"
  283. <log4net>
  284.   <appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
  285.      <mapping>
  286.         <level value="FATAL" />
  287.         <foreColor value="Red, HighIntensity" />
  288.         <backColor value="White, HighIntensity" />
  289.      </mapping>
  290.      <mapping>
  291.         <level value="ERROR" />
  292.         <foreColor value="Red, HighIntensity" />
  293.      </mapping>
  294.      <mapping>
  295.         <level value="DEBUG" />
  296.         <foreColor value="Green, HighIntensity" />
  297.      </mapping>
  298.      <mapping>
  299.         <level value="INFO" />
  300.         <foreColor value="Cyan, HighIntensity" />
  301.      </mapping>
  302.      <mapping>
  303.         <level value="WARN" />
  304.         <foreColor value="Yellow, HighIntensity" />
  305.      </mapping>
  306.      <layout type="log4net.Layout.PatternLayout">
  307.         <conversionPattern value="$MessagePattern" />
  308.      </layout>
  309.   </appender>
  310.   <appender name="EventLogAppender" type="log4net.Appender.EventLogAppender" >
  311.      <applicationName value="$Name" />
  312.      <layout type="log4net.Layout.PatternLayout">
  313.         <conversionPattern value="$MessagePattern" />
  314.      </layout>
  315.   </appender>
  316.   <appender name="TraceAppender" type="log4net.Appender.TraceAppender">
  317.      <layout type="log4net.Layout.PatternLayout">
  318.         <conversionPattern value="$MessagePattern" />
  319.      </layout>
  320.   </appender>
  321.   <appender name="DebugAppender" type="log4net.Appender.DebugAppender">
  322.      <layout type="log4net.Layout.PatternLayout">
  323.         <conversionPattern value="$MessagePattern" />
  324.      </layout>
  325.   </appender>
  326.   <appender name="FileAppender" type="log4net.Appender.FileAppender">
  327.      <file value="$Folder\$Name.Log" />
  328.      <appendToFile value="true" />
  329.      <lockingModel type="log4net.Appender.FileAppender+$LockMode" />
  330.      <layout type="log4net.Layout.PatternLayout">
  331.         <conversionPattern value="$MessagePattern" />
  332.      </layout>
  333.   </appender>
  334.   <appender name="XmlAppender" type="log4net.Appender.FileAppender">
  335.      <file value="$Folder\$Name.xml" />
  336.      <appendToFile value="false" />
  337.      <lockingModel type="log4net.Appender.FileAppender+$LockMode" />
  338.      <layout type="log4net.Layout.XmlLayout">
  339.         <Header value="&lt;?xml version='1.0' ?&gt;
  340. $xslt
  341. &lt;events version='1.2' xmlns='http`://logging.apache.org/log4net/schemas/log4net-events-1.2'&gt;
  342. "/>
  343.         <Footer value="&lt;/events&gt;"/>
  344.      </layout>
  345.   </appender>
  346.   <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
  347.      <file value="$Folder\$Name.Log" />
  348.      <appendToFile value="true" />
  349.      <maximumFileSize value="250KB" />
  350.      <maxSizeRollBackups value="2" />
  351.      <lockingModel type="log4net.Appender.FileAppender+$LockMode" />
  352.      <layout type="log4net.Layout.PatternLayout">
  353.         <conversionPattern value="$MessagePattern" />
  354.      </layout>
  355.   </appender>
  356.   <appender name="RollingXmlAppender" type="log4net.Appender.RollingFileAppender">
  357.      <file value="$Folder\$Name.xml" />
  358.      <appendToFile value="true" />
  359.      <maximumFileSize value="500KB" />
  360.      <maxSizeRollBackups value="2" />
  361.      <lockingModel type="log4net.Appender.FileAppender+$LockMode" />
  362.      <layout type="log4net.Layout.XmlLayout">
  363.         <prefix value="" />
  364.      </layout>
  365.   </appender>
  366.   <appender name="UdpAppender" type="log4net.Appender.UdpAppender">
  367.      <RemoteAddress value="localhost" />
  368.      <RemotePort value="8080" />
  369.      <Encoding value="utf-8" />
  370.      <layout type="log4net.Layout.XmlLayout">
  371.         <Prefix value="" />
  372.      </layout>
  373.      <threshold value="DEBUG" />
  374.   </appender>
  375.   <appender name="UdpLog4JAppender" type="log4net.Appender.UdpAppender">
  376.      <RemoteAddress value="127.0.0.1" />
  377.      <RemotePort value="8080" />
  378.      <Encoding value="utf-8" />
  379.      <layout type="log4net.Layout.XmlLayoutSchemaLog4j, log4net" />
  380.      <threshold value="DEBUG" />
  381.   </appender>
  382.   <appender name="SmtpAppender" type="log4net.Appender.SmtpAppender">
  383.      <to value="$EmailTo" />
  384.      <from value="PoshLogger@$Domain" />
  385.      <subject value="PowerShell Logger Message" />
  386.      <smtpHost value="$PSEmailServer" />
  387.      <bufferSize value="512" />
  388.      <lossy value="true" />
  389.      <evaluator type="log4net.Core.LevelEvaluator">
  390.         <threshold value="WARN"/>
  391.      </evaluator>
  392.      <layout type="log4net.Layout.PatternLayout">
  393.         <conversionPattern value="%newline$MessagePattern%newline%newline" />
  394.      </layout>
  395.   </appender>
  396.   <root>
  397.      <level value="DEBUG" />
  398.   </root>
  399.   <logger name="$Name">
  400.      <level value="$Level" />
  401.      $AppenderRefs
  402.   </logger>
  403. </log4net>
  404. "@
  405.       [log4net.Config.XmlConfigurator]::Configure( $config.log4net )
  406.    }
  407.    elseif($Loggers -and @($Loggers).Count -eq 1) {
  408.       $script:Logger = @($Loggers)[0]
  409.    }
  410. }
  411.  
  412. function Set-Logger {
  413. param(
  414.    [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
  415.    [log4net.Core.LogImpl]$Logger
  416. )
  417.    $script:Logger = $Logger
  418. }
  419.  
  420. function Close-Logger {
  421. param(
  422.    [Parameter(Mandatory=$false, ValueFromPipeline=$true)]
  423.    [log4net.Core.LogImpl]$Logger
  424. )
  425. PROCESS {
  426.    if($Logger) {
  427.       $Logger.Logger.CloseNestedAppenders()
  428.       $Logger.Logger.RemoveAllAppenders()
  429.    } else {
  430.       [log4net.LogManager]::Shutdown()
  431.    }
  432. }
  433. }
  434.  
  435.  
  436.  
  437. function Push-LogContext {
  438. param(
  439.    [Parameter(Mandatory=$true)]
  440.    [string]$Name
  441. )
  442.    [log4net.NDC]::Push($Name)
  443. }
  444. function Pop-LogContext {
  445.    [log4net.NDC]::Pop()
  446. }
  447.  
  448. function Write-DebugLog {
  449. [CmdletBinding()]
  450. param(
  451.     [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
  452.     [Alias('Msg')]
  453.     [AllowEmptyString()]
  454.     [System.String]
  455.     ${Message}
  456. ,
  457.    [Parameter(Mandatory=$false, Position=99)]
  458.    ${Logger})
  459.  
  460. begin
  461. {
  462.     try {
  463.         if($PSBoundParameters.ContainsKey("Logger")) {
  464.             if($Logger -is [log4net.Core.LogImpl]) { Set-Logger $Logger } else { $script:Logger = Get-Logger "$Logger" }
  465.             $null = $PSBoundParameters.Remove("Logger")
  466.         }
  467.        
  468.         $outBuffer = $null
  469.         if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
  470.         {
  471.             $PSBoundParameters['OutBuffer'] = 1
  472.         }
  473.         $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Write-Debug', [System.Management.Automation.CommandTypes]::Cmdlet)
  474.         $scriptCmd = {& $wrappedCmd @PSBoundParameters }
  475.         $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
  476.         $steppablePipeline.Begin($PSCmdlet)
  477.     } catch {
  478.         throw
  479.     }
  480. }
  481.  
  482. process
  483. {
  484.     try {
  485.         $script:logger.debug($Message) #Write-Debug
  486.         $steppablePipeline.Process($_)
  487.     } catch {
  488.         throw
  489.     }
  490. }
  491.  
  492. end
  493. {
  494.     try {
  495.         $steppablePipeline.End()
  496.     } catch {
  497.         throw
  498.     }
  499. }
  500. <#
  501.  
  502. .ForwardHelpTargetName Write-Debug
  503. .ForwardHelpCategory Cmdlet
  504.  
  505. #>
  506. }
  507. function Write-VerboseLog {
  508.  
  509. [CmdletBinding()]
  510. param(
  511.     [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
  512.     [Alias('Msg')]
  513.     [AllowEmptyString()]
  514.     [System.String]
  515.     ${Message}
  516. ,
  517.    [Parameter(Mandatory=$false, Position=99)]
  518.    ${Logger})
  519.  
  520. begin
  521. {
  522.     try {
  523.         if($PSBoundParameters.ContainsKey("Logger")) {
  524.             if($Logger -is [log4net.Core.LogImpl]) { Set-Logger $Logger } else { $script:Logger = Get-Logger "$Logger" }
  525.             $null = $PSBoundParameters.Remove("Logger")
  526.         }
  527.  
  528.         $outBuffer = $null
  529.         if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
  530.         {
  531.             $PSBoundParameters['OutBuffer'] = 1
  532.         }
  533.         $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Write-Verbose', [System.Management.Automation.CommandTypes]::Cmdlet)
  534.         $scriptCmd = {& $wrappedCmd @PSBoundParameters }
  535.         $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
  536.         $steppablePipeline.Begin($PSCmdlet)
  537.     } catch {
  538.         throw
  539.     }
  540. }
  541.  
  542. process
  543. {
  544.     try {
  545.         $script:logger.info($Message)
  546.         $steppablePipeline.Process($_)
  547.     } catch {
  548.         throw
  549.     }
  550. }
  551.  
  552. end
  553. {
  554.     try {
  555.         $steppablePipeline.End()
  556.     } catch {
  557.         throw
  558.     }
  559. }
  560. <#
  561.  
  562. .ForwardHelpTargetName Write-Verbose
  563. .ForwardHelpCategory Cmdlet
  564.  
  565. #>
  566. }
  567. function Write-WarningLog {
  568. [CmdletBinding()]
  569. param(
  570.     [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
  571.     [Alias('Msg')]
  572.     [AllowEmptyString()]
  573.     [System.String]
  574.     ${Message}
  575. ,
  576.    [Parameter(Mandatory=$false, Position=99)]
  577.    ${Logger})
  578.  
  579. begin
  580. {
  581.     try {
  582.         if($PSBoundParameters.ContainsKey("Logger")) {
  583.             if($Logger -is [log4net.Core.LogImpl]) { Set-Logger $Logger } else { $script:Logger = Get-Logger "$Logger" }
  584.             $null = $PSBoundParameters.Remove("Logger")
  585.         }
  586.  
  587.         $outBuffer = $null
  588.         if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
  589.         {
  590.             $PSBoundParameters['OutBuffer'] = 1
  591.         }
  592.         $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Write-Warning', [System.Management.Automation.CommandTypes]::Cmdlet)
  593.         $scriptCmd = {& $wrappedCmd @PSBoundParameters }
  594.         $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
  595.         $steppablePipeline.Begin($PSCmdlet)
  596.     } catch {
  597.         throw
  598.     }
  599. }
  600.  
  601. process
  602. {
  603.     try {
  604.         $script:logger.warn($Message)  #Write-Warning
  605.         $steppablePipeline.Process($_)
  606.     } catch {
  607.         throw
  608.     }
  609. }
  610.  
  611. end
  612. {
  613.     try {
  614.         $steppablePipeline.End()
  615.     } catch {
  616.         throw
  617.     }
  618. }
  619. <#
  620.  
  621. .ForwardHelpTargetName Write-Warning
  622. .ForwardHelpCategory Cmdlet
  623.  
  624. #>
  625. }
  626. function Write-ErrorLog {
  627. [CmdletBinding(DefaultParameterSetName='NoException')]
  628. param(
  629.     [Parameter(ParameterSetName='WithException', Mandatory=$true)]
  630.     [System.Exception]
  631.     ${Exception},
  632.  
  633.     [Parameter(ParameterSetName='NoException', Mandatory=$true, Position=0, ValueFromPipeline=$true)]
  634.     [Parameter(ParameterSetName='WithException')]
  635.     [Alias('Msg')]
  636.     [AllowNull()]
  637.     [AllowEmptyString()]
  638.     [System.String]
  639.     ${Message},
  640.  
  641.     [Parameter(ParameterSetName='ErrorRecord', Mandatory=$true)]
  642.     [System.Management.Automation.ErrorRecord]
  643.     ${ErrorRecord},
  644.  
  645.     [Parameter(ParameterSetName='NoException')]
  646.     [Parameter(ParameterSetName='WithException')]
  647.     [System.Management.Automation.ErrorCategory]
  648.     ${Category},
  649.  
  650.     [Parameter(ParameterSetName='WithException')]
  651.     [Parameter(ParameterSetName='NoException')]
  652.     [System.String]
  653.     ${ErrorId},
  654.  
  655.     [Parameter(ParameterSetName='NoException')]
  656.     [Parameter(ParameterSetName='WithException')]
  657.     [System.Object]
  658.     ${TargetObject},
  659.  
  660.     [System.String]
  661.     ${RecommendedAction},
  662.  
  663.     [Alias('Activity')]
  664.     [System.String]
  665.     ${CategoryActivity},
  666.  
  667.     [Alias('Reason')]
  668.     [System.String]
  669.     ${CategoryReason},
  670.  
  671.     [Alias('TargetName')]
  672.     [System.String]
  673.     ${CategoryTargetName},
  674.  
  675.     [Alias('TargetType')]
  676.     [System.String]
  677.     ${CategoryTargetType}
  678. ,
  679.    [Parameter(Mandatory=$false, Position=99)]
  680.    ${Logger})
  681.  
  682. begin
  683. {
  684.     try {
  685.         if($PSBoundParameters.ContainsKey("Logger")) {
  686.             if($Logger -is [log4net.Core.LogImpl]) { Set-Logger $Logger } else { $script:Logger = Get-Logger "$Logger" }
  687.             $null = $PSBoundParameters.Remove("Logger")
  688.         }
  689.  
  690.         $outBuffer = $null
  691.         if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
  692.         {
  693.             $PSBoundParameters['OutBuffer'] = 1
  694.         }
  695.         $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Write-Error', [System.Management.Automation.CommandTypes]::Cmdlet)
  696.         $scriptCmd = {& $wrappedCmd @PSBoundParameters }
  697.         $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
  698.         $steppablePipeline.Begin($PSCmdlet)
  699.     } catch {
  700.         throw
  701.     }
  702. }
  703.  
  704. process
  705. {
  706.     try {
  707.         $script:logger.error($Message,$Exception) #Write-Error
  708.         $steppablePipeline.Process($_)
  709.     } catch {
  710.         throw
  711.     }
  712. }
  713.  
  714. end
  715. {
  716.     try {
  717.         $steppablePipeline.End()
  718.     } catch {
  719.         throw
  720.     }
  721. }
  722. <#
  723.  
  724. .ForwardHelpTargetName Write-Error
  725. .ForwardHelpCategory Cmdlet
  726.  
  727. #>
  728. }
  729. function Write-HostLog {
  730. [CmdletBinding()]
  731. param(
  732.     [Parameter(Position=0, ValueFromPipeline=$true, ValueFromRemainingArguments=$true)]
  733.     [System.Object]
  734.     ${Object},
  735.  
  736.     [Switch]
  737.     ${NoNewline},
  738.  
  739.     [System.Object]
  740.     ${Separator} = $OFS,
  741.  
  742.     [System.ConsoleColor]
  743.     ${ForegroundColor},
  744.  
  745.     [System.ConsoleColor]
  746.     ${BackgroundColor}
  747. ,
  748.    [Parameter(Mandatory=$false, Position=99)]
  749.    ${Logger})
  750.  
  751. begin
  752. {
  753.     try {
  754.         if($PSBoundParameters.ContainsKey("Logger")) {
  755.             if($Logger -is [log4net.Core.LogImpl]) { Set-Logger $Logger } else { $script:Logger = Get-Logger "$Logger" }
  756.             $null = $PSBoundParameters.Remove("Logger")
  757.         }
  758.  
  759.         $outBuffer = $null
  760.         if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
  761.         {
  762.             $PSBoundParameters['OutBuffer'] = 1
  763.         }
  764.         $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Write-Host', [System.Management.Automation.CommandTypes]::Cmdlet)
  765.         $scriptCmd = {& $wrappedCmd @PSBoundParameters }
  766.         $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
  767.         $steppablePipeline.Begin($PSCmdlet)
  768.     } catch {
  769.         throw
  770.     }
  771. }
  772.  
  773. process
  774. {
  775.     try {
  776.         $script:logger.info(($Object -join $Separator))  #Write-Verbose
  777.         $steppablePipeline.Process($_)
  778.     } catch {
  779.         throw
  780.     }
  781. }
  782.  
  783. end
  784. {
  785.     try {
  786.         $steppablePipeline.End()
  787.     } catch {
  788.         throw
  789.     }
  790. }
  791. <#
  792.  
  793. .ForwardHelpTargetName Write-Host
  794. .ForwardHelpCategory Cmdlet
  795.  
  796. #>
  797. }
  798.  
  799. Set-Alias Write-Debug Write-DebugLog
  800. Set-Alias Write-Verbose Write-VerboseLog
  801. Set-Alias Write-Warning Write-WarningLog
  802. Set-Alias Write-Error Write-ErrorLog
  803. #Set-Alias Write-Host Write-HostLog
  804.  
  805. Export-ModuleMember -Function * -Alias *
  806.  
  807. $script:Logger = Get-Logger "PowerShellLogger" -RollingFile
  808.  
  809. ## THIS IS THE DEFAULT LOGGER. CONFIGURE AS YOU SEE FIT

Submit a correction or amendment below (
click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:


Remember me