带交换的 Powershell——如何将所有详细输出附加到文件中 [英] Powershell with exchange-- How do I append all verbose output to a file

查看:25
本文介绍了带交换的 Powershell——如何将所有详细输出附加到文件中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在我的脚本中添加一些日志记录.任何建议将不胜感激.首先 - 我想在出现问题时添加错误日志.

例如,当找不到用户时,会抛出以下错误:

无法执行操作,因为在HQ-DC-6.domain.com"上找不到对象asdfa".+ CategoryInfo : NotSpecified: (0:Int32) [Set-RemoteMailbox], ManagementObjectNotFoundException+ FullQualifiedErrorId : 47285FC7,Microsoft.Exchange.Management.RecipientTasks.SetRemoteMailbox+ PSComputerName : hq-cas2.domain.com

================================

$users = ForEach ($user in $(Get-Content 'C:Users	estDocumentsPowershell ScriptsOffboardUsers.txt')) {$tmpname = Get-RemoteMailbox -Identity $user |选择对象 -ExpandProperty 名称$tmpDisplayName = Get-RemoteMailbox -Identity $user |选择对象 -ExpandProperty 显示名称Set-RemoteMailbox -Identity $user -Name ("_" + "$tmpname") >>错误日志Set-RemoteMailbox -Identity $user -DisplayName ("_" + "$tmpDisplayName") >>错误日志Set-RemoteMailbox -Identity $user -HiddenFromAddressListsEnabled $true >>错误日志}

解决方案

本文于 2017-07-18 完全修订为新的

日志文件

示例命令在日志文件中记录了以下信息:

2017-07-13 PowerShell 版本:5.1.15063.483,进程开始:2017-07-13 15:39:4415:39:46.75 日志条目版本:02.00.01,命令行:C:UsersUserScriptsLog-EntryLog-Entry.ps115:39:46.80 示例:15:39:46.94 写主机通常不显示的几个例子: $Null @() @() @(@(), @()) @($Null)15:39:46.95 注 1:空字符串:日志条目也不显示(因为您不希望引用每条评论).15:39:46.98 如果您想显示一个(可能的)空字符串,请使用 -QuoteString: ""15:39:47.00 注 2:嵌入另一个数组的空数组:@() 被 PowerShell 扁平化(而不是写日志).15:39:47.01 为防止这种情况在嵌入数组前使用逗号:@(@())15:39:47.05 一个哈希表:@{一个 = 1,三个 = 3,两个 = 2}15:39:47.06 递归哈希表:@{一 = @{一 = @{一 = 1,三 = 3,二 = 2},三 = 3,二 = 2},三 = 3,二 = 2}15:39:47.10 字符数组:@(H, a, l, l, o, , W, o, r, l, d)15:39:47.11 以下行产生一个错误,该错误被记录在日志文件中:51,23 处的错误:找不到路径C:NoSuchFile.txt",因为它不存在.15:39:47.15 文件:$Null15:39:47.16 开关 -FlushErrors 可防止记录错误:15:39:47.17 文件:$Null15:39:47.17 以下是两个内联日志示例(返回?"之前的对象):15:39:47.18 高度:3 英寸15:39:47.19 宽度:4 英寸15:39:47.19 或者一个显示/日志行分布在多个代码行上:15:39:47.20 外围:14 英寸15:39:47.27结束(执行时间:00:00:00.5781145,处理时间:00:00:03.1067112)

I am trying to add some logging into my script. Any advice would be much appreciated. To start out- I'd like to add an error log when something goes amiss.

For instance when a user cannot be found the following error throws:

The operation couldn't be performed because object 'asdfa' couldn't be found on 'HQ-DC-6.domain.com'. + CategoryInfo : NotSpecified: (0:Int32) [Set-RemoteMailbox], ManagementObjectNotFoundException + FullyQualifiedErrorId : 47285FC7,Microsoft.Exchange.Management.RecipientTasks.SetRemoteMailbox + PSComputerName : hq-cas2.domain.com

==============================

$users = ForEach ($user in $(Get-Content 'C:Users	estDocumentsPowershell ScriptsOffboardUsers.txt')) {

$tmpname = Get-RemoteMailbox -Identity $user | Select-Object -ExpandProperty Name
$tmpDisplayName = Get-RemoteMailbox -Identity $user | Select-Object -ExpandProperty DisplayName

Set-RemoteMailbox -Identity $user -Name ("_" + "$tmpname") >> error.log
Set-RemoteMailbox -Identity $user -DisplayName ("_" + "$tmpDisplayName") >> error.log
Set-RemoteMailbox -Identity $user -HiddenFromAddressListsEnabled $true >> error.log

}

解决方案

This article is completely revised 2017-07-18 as the new Log-Entry solution replaces the former Write-Log solution which will not be further updated. See also: Migrating from Write-Log.


In general, I find that logging is underestimated for Microsoft scripting languages. Not only at design time of a script (or cmdlet) logging comes in handy but when the script gets deployed and something goes wrong you often wish that you had much better logging in place.
That's why I think that scripting languages as PowerShell (as well as its predecessor VBScript) should actually come with a more sophisticated native logging capabilities than what is available now.

Best practice

Even before PowerShell existed, I had a similar need for a adequate logging function in VBScript. As a matter of fact, some of the concepts I was using for VBScript, I am still using in PowerShell. Meanwhile, I have extended my logging solution with a whole list of improvements and requirements as I expect a log function to be:

  • Robust and never cause the actual cmdlet to fail unexpectedly (even
    when e.g. the access to the log file is for some reason denied)

  • Simple to invoke and possibly be used as a
    Write-Host command replacement

  • Resolve all data types and reveal the content

  • Capture unexpected native script errors

  • Capable to pass-through objects for inline logging to minimize additional code lines

  • Have an accurate (10ms) timestamp per entry for performance trouble
    shooting

  • Standard capturing troubleshooting information like:

    • Script version

    • PowerShell version

    • When it was ran (process start time)

    • How (parameters) and from where (location) it was ran

  • Appended append information to a configurable log file which doesn't grow indefinitely

  • Downwards compatible with PowerShell version 2

Robust

If you want to go for a robust logging solution, you probably want to go with the native Start-Transcript cmdlet but you will probably find out that the Start-Transcript lacks features, like timestamps, that you might expect from a proper logging cmdlet. You could go for a 3rd party solution but this usually means extra installation procedures and dependencies.
So you decide to write it yourself but even the simplest solution where you just write information to a file might already cause an issue in the field: the file might not be accessible. It might even exist but your script is triggered twice and multiple instances run at the same time the log file might be open by one of instances and access is denied from the other instance (see e.g.: Powershell Scheduled Tasks conflicts?). And just at this point, logging should actually help you to troubleshoot what is going on as a repetitive trigger might also cause unexpected behavior in the script itself. For this particular example, the solution I present here buffers the output until it is able to write. But there are a lot more traps in writing a logging cmdlet and correctly formatting the output.

Log-Entry

I have put the whole solution in a Log-Entry.ps1 framework consisting out of a few major parts:

  1. A help header - and a Main function template with a few examples
  2. A My object that contains some script - and logging definitions
  3. Four functions to control the logging:
    • Log-Entry (alias Log) to log information and objects
    • Set-LogFile (alias LogFile) to set the location of the log file
    • End-Script (alias End) which might be used to nicely close the session
    • ConvertTo-Text (alias CText) to resolve objects

For the latest Log-Entry.ps1 version, see: https://github.com/iRon7/Log-Entry.

Usage

Download the above Log-Entry.ps1 framwork and replace the examples in the Main {} function with your own script. Everywhere you would like to display and log information, use the Log command (similar to the Write-Host command syntax).
Run the script and check the log file at: %Temp%<ScriptName>.Log

Syntax

For details on the syntax, see: the readme.md at https://github.com/iRon7/Log-Entry

Example

Here are a few commands that show some of the features of the Log-Entry framework:

LogFile .Test.log                  # Redirect the log file location (Optional)
Log -Color Yellow "Examples:"
Log "Several examples that usually aren't displayed by Write-Host:" $NotSet @() @(@()) @(@(), @()) @($Null)
Log -Indent 1 "Note 1: An empty string:" "" "isn't displayed by Log-Entry either (as you usually do not want every comment quoted)."
Log -Indent 2 "In case you want to reveal a (possible) empty string, use -QuoteString:" -NoNewline; Log -QuoteString ""
Log -Indent 1 "Note 2: An empty array embedded in another array:" @(@()) "is flattened by PowerShell (and not Write-Log)."
Log -Indent 2 "To prevent this use a comma in front of the embbed array: " @(,@())
Log "A hashtable:" @{one = 1; two = 2; three = 3}
Log "A recursive hashtable:" @{one = @{one = @{one = 1; two = 2; three = 3}; two = 2; three = 3}; two = 2; three = 3} -Expand -Depth:9
Log "Character array:" "Hallo World".ToCharArray()
Log-Verbose "The following line produces a error which is captured in the log file:"
$File = Log "File:" (Get-ChildItem "C:NoSuchFile.txt" -ErrorAction SilentlyContinue)
Log-Verbose "The switch -FlushErrors prevents the error being logged:"
$File = Log "File:" (Get-ChildItem "C:NoSuchFile.txt" -ErrorAction SilentlyContinue) -FlushErrors
Log "Below are two inline log examples (the object preceding the ""?"" is returned):"
$Height = Log "Height:" 3 ? "Inch"
$Width  = Log "Width:"  4 ? "Inch"
Log-Verbose "Or one display/log line spread over multiple code lines:"
Log "Periphery:" -NoNewline
$Periphery = Log (2 * $Height + 2 * $Width) ? -Color Green -NoNewline
Log "Inch"
Log-Debug "Password:" $Password "(This will not be shown and captured unless the common -Debug argument is supplied)"

Display

The example commands are displayed in the following format:

Log file

The example commands record the following information in the log file:

2017-07-13  PowerShell version: 5.1.15063.483, process start: 2017-07-13 15:39:44
15:39:46.75 Log-Entry version: 02.00.01, command line: C:UsersUserScriptsLog-EntryLog-Entry.ps1 
15:39:46.80 Examples:
15:39:46.94 Several examples that usually aren't displayed by Write-Host: $Null @() @() @(@(), @()) @($Null)
15:39:46.95         Note 1: An empty string: isn't displayed by Log-Entry either (as you do not want every comment quoted).
15:39:46.98                 In case you want to reveal a (possible) empty string, use -QuoteString: ""
15:39:47.00         Note 2: An empty array embedded in another array: @() is flattened by PowerShell (and not Write-Log).
15:39:47.01                 To prevent this use a comma in front of the embbed array:  @(@())
15:39:47.05 A hashtable: @{one = 1, three = 3, two = 2}
15:39:47.06 A recursive hashtable: @{
                one = @{
                    one = @{
                        one = 1, 
                        three = 3, 
                        two = 2
                    }, 
                    three = 3, 
                    two = 2
                }, 
                three = 3, 
                two = 2
            }
15:39:47.10 Character array: @(H, a, l, l, o,  , W, o, r, l, d)
15:39:47.11 The following line produces a error which is captured in the log file:
Error at 51,23: Cannot find path 'C:NoSuchFile.txt' because it does not exist.
15:39:47.15 File: $Null
15:39:47.16 The switch -FlushErrors prevents the error being logged:
15:39:47.17 File: $Null
15:39:47.17 Below are two inline log examples (the object preceding the "?" is returned):
15:39:47.18 Height: 3 Inch
15:39:47.19 Width: 4 Inch
15:39:47.19 Or one display/log line spread over multiple code lines:
15:39:47.20 Periphery: 14 Inch
15:39:47.27 End (Execution time: 00:00:00.5781145, Process time: 00:00:03.1067112)

这篇关于带交换的 Powershell——如何将所有详细输出附加到文件中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆