Quantcast
Channel: The Official Scripting Guys Forum! forum
Viewing all articles
Browse latest Browse all 15028

Scripting Logging in PowerShell (discussion)

$
0
0

Hello everyone,

I'm still fairly new to PowerShell;  I've only really been diving into it hard for about three weeks now.  I have a lot of experience scripting and programming in other languages, so it's mostly a matter of just getting a feel for the quirks of the new shell, getting to know my way around the cmdlets that are already written, etc.

One thing that I'm still mulling over is how best to approach log output in my scripts.  For years, I've used this "Output" sub in my VBScripts instead of WScript.Echo.  If I want a log file, I simply open it and assign the stream to the g_objLogFile global variable, and the function takes care of the rest.  The g_blnConsole global variable is just True if the script was launched with cscript, False otherwise.  The subroutine prepends timestamps on non-blank lines in the file, but otherwise leaves the console output alone.

Sub Output(strMessage)
  On Error Resume Next
  If (g_blnConsole) Then WScript.Echo strMessage
  If (strMessage <> "") Then strMessage = CStr(Now) & " - " & strMessage
  If (LCase(TypeName(g_objLogFile)) = "textstream") Then g_objLogFile.Writeline strMessage
  On Error Goto 0
End Sub

When I set out to reproduce this functionality in PowerShell, it turned out to be more complicated than I would have thought.  Here's what I've learned, pondered and written so far:

PowerShell v3 allows you to redirect almost every stream (except Progress) to a file with *> , but v2 only supports redirection of the Output and Error streams (and most of our servers don't have v3 installed at this point, so I'm trying to make all scripts V2-compatible for the time being).  If you redirect the streams in that manner, though, you lose your console output.

You can write proxy functions to override the behavior of default Cmdlets, and this is what I tried next. Ideally, I would want to produce a function that intercepts all console output, and sends it off to a file, but that is very tricky.

Overriding Out-Default sort of works, butonly if the proxy function is loaded into memory before your script file is executed.  It took me a while to get my head wrapped around this:  PowerShell appends| Out-Default to any command entered at the console, not to every line of a script.  By the time your script execution starts, PowerShell has already set up the pipeline that sends your script's output to the Out-Default cmdlet, and if you create an Out-Default function from inside the script, it won't take effect until the next console command, after the script finishes.  Also, even if Out-Default is overridden, this only seems to catch the results of the Output and Error streams, for some reason.  Calls to Write-Warning, Write-Debug and Write-Verbose did not trigger execution of Out-Default (or at least, not the proxy function with that name).

Overriding Out-Host does not seem to work at all.  I'm not sure why, but the proxy function is never executed unless you explicitly pipe to it inside the script.

Overriding Write-Host, Write-Error, Write-Warning, Write-Verbose and Write-Debug works fine, but only if you make sure that all of your script output gets piped explicitly through those commands.  If you just allow something to pass out of your scripts streams to the host, it'll display in the console (via Out-Default, a formatting cmdlet, and eventually Out-Host), and never find its way to the log file.  This results in an outer "shell" script that is responsible for all user and log file interaction, while any scripts called by it can behave like normal PowerShell code, writing to streams and returning objects.

So far, this is the best I've been able to accomplish, and I put it into a module that you can see at http://gallery.technet.microsoft.com/scriptcenter/Write-timestamped-output-4ff1565f .

That's pretty much my experience on the subject, but I'd love to know if someone has found a better approach, or sees any flaws with my tests or current code.  How do you make sure your log files aren't missing important information that was only output to the console?


Viewing all articles
Browse latest Browse all 15028

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>