繁体   English   中英

带有交换功能的Powershell-如何将所有详细输出附加到文件

[英]Powershell with exchange— How do I append all verbose output to a file

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

例如,当找不到用户时,将引发以下错误:

由于在“ HQ-DC-6.domain.com”上找不到对象“ asdfa”,因此无法执行该操作。 + CategoryInfo:未指定:(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\test\Documents\Powershell Scripts\OffboardUsers.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

}

由于新的Log-Entry解决方案替代了之前的Write-Log解决方案,因此将对其进行全面修订,并于2017年7月18日进行了修订,该解决方案将不再进行更新。 另请参阅: 从Write-Log迁移


通常,我发现Microsoft脚本语言的日志记录被低估了。 不仅在脚本(或cmdlet)的设计时,日志记录派上用场,而且在脚本被部署且出现问题时,您通常希望您有更好的日志记录。
这就是为什么我认为,像PowerShell(及其前身VBScript)这样的脚本语言实际上应该具有比现在可用的更复杂的本机日志记录功能。

最佳实践

甚至在PowerShell出现之前,我对VBScript中的适当日志功能也有类似的需求。 实际上,我在VBScript中使用的某些概念仍在PowerShell中使用。 同时,我扩展了日志记录解决方案,并提供了完整的改进和要求列表,因为我希望日志功能为:

  • 健壮且决不会导致实际的cmdlet意外失败(甚至
    例如由于某些原因拒绝访问日志文件时)

  • 易于调用,可能用作
    Write-Host命令替换

  • 解决所有数据类型并显示内容

  • 捕获意外的本机脚本错误

  • 能够传递对象以进行内联日志记录,以最大程度地减少其他代码行

  • 每个条目都有准确的(10ms)时间戳,以防性能出现问题
    射击

  • 标准捕获故障排除信息,例如:

    • 脚本版本

    • PowerShell版本

    • 运行时间(进程开始时间)

    • 运行方式(参数)和运行位置(位置)

  • 将信息追加到不会无限增长的可配置日志文件中

  • 向下兼容PowerShell版本2

强大的

如果要使用可靠的日志记录解决方案,则可能要使用本机的Start-Transcript cmdlet,但您可能会发现Start-Transcript缺少正确的日志记录cmdlet可能期望的功能(例如时间戳)。 您可以寻求第三方解决方案,但这通常意味着额外的安装过程和依赖项。
因此,您决定自己编写它,但是即使是仅将信息写入文件的最简单的解决方案,也可能已经在该领域引起问题:该文件可能无法访问。 它甚至可能存在,但是您的脚本被触发了两次,并且多个实例同时运行,一个实例可能打开了日志文件,而另一个实例拒绝了访问(请参阅例如: Powershell Scheduled Tasks冲突? )。 就这一点而言,日志记录实际上应该可以帮助您解决正在发生的事情,因为重复触发还可能导致脚本本身出现意外行为。 对于这个特定的例子,我在这里介绍的解决方案会缓冲输出,直到能够写入为止。 但是在编写日志记录cmdlet并正确格式化输出时还有很多陷阱。

日志输入

我将整个解决方案放入了Log-Entry.ps1框架 ,该框架由几个主要部分组成:

  1. 帮助标题-以及带有一些示例的Main函数模板
  2. 包含一些脚本的My对象-以及日志记录定义
  3. 四个功能来控制日志记录:
    • Log-Entry (别名Log )以记录信息和对象
    • Set-LogFile (别名LogFile )设置日志文件的位置
    • End-Script (别名End ),可以用来很好地关闭会话
    • ConvertTo-Text (别名CText )来解析对象

有关Log-Entry.ps1的最新版本,请参见: https : //github.com/iRon7/Log-Entry

用法

下载上面的Log-Entry.ps1框架,并用您自己的脚本替换Main {}函数中的示例。 您想在任何地方显示和记录信息,请使用Log命令(类似于Write-Host命令语法)。
运行脚本并在以下位置检查日志文件: %Temp%\\<ScriptName>.Log

句法

有关语法的详细信息,请参见: https : //github.com/iRon7/Log-Entry上的readme.md

以下是一些命令,它们显示了Log-Entry框架的某些功能:

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)"

显示

示例命令以以下格式显示:

显示

日志文件

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

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:\Users\User\Scripts\Log-Entry\Log-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)

您可以使用Write-Log功能。 我认为这将是您最好的方法。

此功能由Jason Wasser编写:

<#
.Synopsis
   Write-Log writes a message to a specified log file with the current time stamp.
.DESCRIPTION
   The Write-Log function is designed to add logging capability to other scripts.
   In addition to writing output and/or verbose you can write to a log file for
   later debugging.
.NOTES
   Created by: Jason Wasser @wasserja
   Modified: 11/24/2015 09:30:19 AM  

   Changelog:
    * Code simplification and clarification - thanks to @juneb_get_help
    * Added documentation.
    * Renamed LogPath parameter to Path to keep it standard - thanks to @JeffHicks
    * Revised the Force switch to work as it should - thanks to @JeffHicks

   To Do:
    * Add error handling if trying to create a log file in a inaccessible location.
    * Add ability to write $Message to $Verbose or $Error pipelines to eliminate
      duplicates.
.PARAMETER Message
   Message is the content that you wish to add to the log file. 
.PARAMETER Path
   The path to the log file to which you would like to write. By default the function will 
   create the path and file if it does not exist. 
.PARAMETER Level
   Specify the criticality of the log information being written to the log (i.e. Error, Warning, Informational)
.PARAMETER NoClobber
   Use NoClobber if you do not wish to overwrite an existing file.
.EXAMPLE
   Write-Log -Message 'Log message' 
   Writes the message to c:\Logs\PowerShellLog.log.
.EXAMPLE
   Write-Log -Message 'Restarting Server.' -Path c:\Logs\Scriptoutput.log
   Writes the content to the specified log file and creates the path and file specified. 
.EXAMPLE
   Write-Log -Message 'Folder does not exist.' -Path c:\Logs\Script.log -Level Error
   Writes the message to the specified log file as an error message, and writes the message to the error pipeline.
.LINK
   https://gallery.technet.microsoft.com/scriptcenter/Write-Log-PowerShell-999c32d0
#>
function Write-Log
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true)]
        [ValidateNotNullOrEmpty()]
        [Alias("LogContent")]
        [string]$Message,

        [Parameter(Mandatory=$false)]
        [Alias('LogPath')]
        [string]$Path='C:\Logs\PowerShellLog.log',

        [Parameter(Mandatory=$false)]
        [ValidateSet("Error","Warn","Info")]
        [string]$Level="Info",

        [Parameter(Mandatory=$false)]
        [switch]$NoClobber
    )

    Begin
    {
        # Set VerbosePreference to Continue so that verbose messages are displayed.
        $VerbosePreference = 'Continue'
    }
    Process
    {

        # If the file already exists and NoClobber was specified, do not write to the log.
        if ((Test-Path $Path) -AND $NoClobber) {
            Write-Error "Log file $Path already exists, and you specified NoClobber. Either delete the file or specify a different name."
            Return
            }

        # If attempting to write to a log file in a folder/path that doesn't exist create the file including the path.
        elseif (!(Test-Path $Path)) {
            Write-Verbose "Creating $Path."
            $NewLogFile = New-Item $Path -Force -ItemType File
            }

        else {
            # Nothing to see here yet.
            }

        # Format Date for our Log File
        $FormattedDate = Get-Date -Format "yyyy-MM-dd HH:mm:ss"

        # Write message to error, warning, or verbose pipeline and specify $LevelText
        switch ($Level) {
            'Error' {
                Write-Error $Message
                $LevelText = 'ERROR:'
                }
            'Warn' {
                Write-Warning $Message
                $LevelText = 'WARNING:'
                }
            'Info' {
                Write-Verbose $Message
                $LevelText = 'INFO:'
                }
            }

        # Write log entry to $Path
        "$FormattedDate $LevelText $Message" | Out-File -FilePath $Path -Append
    }
    End
    {
    }
}

用法:

 Write-Log -Message 'Folder does not exist.' -Path c:\Logs\Script.log -Level Error

Write-Log -Message 'Restarting Server.' -Path c:\Logs\Scriptoutput.log

注意:您可以始终为所有详细信息使用此功能的帮助。

希望能帮助到你。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM