我正在尝试在我的脚本中添加一些日志记录。任何建议将不胜感激。首先,我想在出现问题时添加错误日志。
例如,当找不到用户时会抛出以下错误:
无法执行此操作,因为对象' asdfa'无法在' 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\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
}
答案 0 :(得分:2)
本文已完全修订2017-07-18,因为新的Log-Entry
解决方案取代了以前的Write-Log
解决方案,该解决方案将不会进一步更新。另请参阅:Migrating from Write-Log。
通常,我发现Microsoft脚本语言的日志记录被低估了。不仅在脚本(或cmdlet)的设计时,日志就派上用场,但是当脚本部署并出现问题时,您通常希望您有更好的日志记录。
这就是为什么我认为脚本语言如PowerShell(以及它的前身VBScript)实际上应该具有比现在更加复杂的本机日志记录功能。
即使在PowerShell存在之前,我对VBScript中的适当日志记录功能也有类似的需求。事实上,我用于VBScript的一些概念,我仍然在PowerShell中使用。同时,我已经扩展了我的日志记录解决方案,其中包含一系列改进和要求,因为我希望日志功能是:
强大且永远不会导致实际的cmdlet意外失败(甚至是 例如,由于某种原因拒绝访问日志文件)
简单地调用并可能用作
Write-Host
命令替换
解析所有数据类型并显示内容
捕获意外的原生脚本错误
能够传递对象以进行内联日志记录,以最大限度地减少其他代码行
对于性能问题,每个条目都有准确的(10毫秒)时间戳 拍摄
标准捕获故障排除信息,如:
脚本版
PowerShell版本
运行时(处理开始时间)
如何(参数)以及从哪里(位置)运行
附加附加信息到可配置的日志文件,该日志文件无法无限增长
向下兼容PowerShell版本2
如果您想使用强大的日志记录解决方案,您可能希望使用本机Start-Transcript cmdlet,但您可能会发现Start-Transcript
缺少您可能期望的功能,例如时间戳。一个正确的日志记录cmdlet。您可以选择第三方解决方案,但这通常意味着额外的安装过程和依赖关系
因此,您决定自己编写,但即使是最简单的解决方案,您只是将信息写入文件可能已经导致现场问题:文件可能无法访问。它甚至可能存在,但是您的脚本被触发两次,并且多个实例在一个实例打开日志文件的同时运行,而另一个实例拒绝访问(参见例如:Powershell Scheduled Tasks conflicts?)。此时,日志记录实际上应该可以帮助您解决正在发生的事情,因为重复触发器也可能导致脚本本身出现意外行为。对于这个特定的例子,我在这里提出的解决方案缓冲输出,直到它能够写入。但是在编写日志记录cmdlet和正确格式化输出时会有更多陷阱。
我已将整个解决方案放在由Log-Entry.ps1
framework组成的几个主要部分中:
Main
功能模板My
对象Log-Entry
(别名Log
)来记录信息和对象Set-LogFile
(别名LogFile
)设置日志文件的位置End-Script
(别名End
)可能会用来很好地关闭会话ConvertTo-Text
(别名CText
)来解析对象有关最新的Log-Entry.ps1
版本,请参阅:https://github.com/iRon7/Log-Entry。
下载上面的Log-Entry.ps1
framwork并使用您自己的脚本替换Main {}
函数中的示例。您希望显示和记录信息的任何地方,使用Log
命令(类似于Write-Host
命令语法)。
运行脚本并检查日志文件:%Temp%\<ScriptName>.Log
有关语法的详细信息,请参阅:readme.md上的https://github.com/iRon7/Log-Entry
示例强>
以下是一些显示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)
答案 1 :(得分:1)
您可以使用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
注意:您可以始终对此功能使用get-help来获取所有详细信息。
希望它有所帮助。