在Powershell中创建日志文件


71

我有下面的代码,当前它加载屏幕上的所有信息。我希望它登录到D:\ Apps \ Logs上的日志文件。

日志文件需要具有要加载的计算机的名称-因此COMPUTERNAME.log

知道我该怎么做吗?

谢谢

$computer = gc env:computername

$onetcp = ((get-childitem c:\windows\system32\drivers\tcpip.sys).Versioninfo.ProductMajorPart).tostring() $twotcp = ((get-childitem c:\windows\system32\drivers\tcpip.sys).Versioninfo.ProductMinorPart).tostring() $threetcp = ((get-childitem c:\windows\system32\drivers\tcpip.sys).Versioninfo.ProductBuildPart).tostring() $fourtcp = ((get-childitem c:\windows\system32\drivers\tcpip.sys).Versioninfo.ProductPrivatePart).tostring()


$onedfsr = ((get-childitem c:\windows\system32\dfsrs.exe).Versioninfo.ProductMajorPart).tostring() $twodfsr = ((get-childitem c:\windows\system32\dfsrs.exe).Versioninfo.ProductMinorPart).tostring() $threedfsr = ((get-childitem c:\windows\system32\dfsrs.exe).Versioninfo.ProductBuildPart).tostring() $fourdfsr = ((get-childitem c:\windows\system32\dfsrs.exe).Versioninfo.ProductPrivatePart).tostring()

write-host TCPIP.sys Version on $computer is: "$onetcp.$twotcp.$threetcp.$fourtcp" Write-Host write-host DFSRS.exe Version on $computer is: "$onedfsr.$twodfsr.$threedfsr.$fourdfsr"

Write-Host

If (get-wmiobject win32_share | where-object {$_.Name -eq "REMINST"}) {   Write-Host "The REMINST share exists on $computer" } Else {   Write-Host "The REMINST share DOES NOT exist on $computer - Please create as per standards"  }   Write-Host

$hotfix1 = Get-HotFix -Id KB2450944 -ErrorAction SilentlyContinue $hotfix2 = Get-HotFix -Id KB2582284 -ErrorAction SilentlyContinue $hotfix3 = Get-HotFix -Id KB979808 -ErrorAction SilentlyContinue

If ($hotfix1) {     Write-Host "Hotfix KB2450944 is installed"
-BackgroundColor Green -ForegroundColor Black   } else {    Write-Host "Hotfix KB2450944 is NOT installed - Please ensure you install this hotfix" -ForegroundColor "red"   }


If ($hotfix2) {     Write-Host "Hotfix KB2582284 is installed"
-BackgroundColor Green -ForegroundColor Black   } else {    Write-Host "Hotfix KB2582284 is NOT installed - Please ensure you install this hotfix" -ForegroundColor "red"   }

If ($hotfix3) {     Write-Host "Hotfix KB979808 is installed"
-BackgroundColor Green -ForegroundColor Black   } else {    Write-Host "Hotfix KB979808 is NOT installed - Please ensure you install this hotfix" -ForegroundColor "red"    }

日志:术语“日志”不能识别为cmdlet,脚本文件或可运行程序的名称。检查包含的名称的拼写,确认路径正确,然后重试。您也有日志功能吗?
Hecatonchires

Answers:


145

将其放在文件顶部:

$Logfile = "D:\Apps\Logs\$(gc env:computername).log"

Function LogWrite
{
   Param ([string]$logstring)

   Add-content $Logfile -value $logstring
}

然后将您的Write-host呼叫替换为LogWrite


谢谢-可以正常工作,但现在不显示TCPIP.sys版本-只是显示“ TCPIP.sys”-与DFSR.exe相同。我将Write-Host更改为LogWrite,但是这两个未在日志文件中显示版本。另外,您知道我每次运行时如何重新写入日志文件的想法吗?当前,它会附加日志文件。如果它每次只能创建一个新的文件,则希望这样做。谢谢。
lara400

3
对于对象的属性,您需要将整个对象括在括号中,并在前面加一个$。尝试将其更改为:$(TCPIP.sys)
JNK

1
要使日志文件每次都重新制作,您需要在顶部添加另一个部分以删除/创建该文件(如果存在)。
JNK

2
只是附带说明,您可以使用$ env变量将计算机名嵌入字符串中,而无需使用get-content和变量赋值。Write-Host "My local computer name is: $env:computername"
谢伊·利维

3
我还喜欢使用-passthrough标志,以便日志记录也输出到Shell窗口。
JohnZaj 2012年

68

一种将这些原理进一步发展的功能。

  1. Add的时间戳-没有时间戳就不能有日志。
  2. 添加一个级别(默认情况下使用INFO)意味着您可以突出显示大问题。
  3. 允许可选的控制台输出。如果您未设置日志目标,则只需将其抽出即可。

    Function Write-Log {
        [CmdletBinding()]
        Param(
        [Parameter(Mandatory=$False)]
        [ValidateSet("INFO","WARN","ERROR","FATAL","DEBUG")]
        [String]
        $Level = "INFO",
    
        [Parameter(Mandatory=$True)]
        [string]
        $Message,
    
        [Parameter(Mandatory=$False)]
        [string]
        $logfile
        )
    
        $Stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss")
        $Line = "$Stamp $Level $Message"
        If($logfile) {
            Add-Content $logfile -Value $Line
        }
        Else {
            Write-Output $Line
        }
    }
    

21

我相信这是将屏幕上所有内容放入文件的最简单方法。这是本机PS CmdLet,因此您无需在脚本中进行任何更改

Start-Transcript -Path Computer.log

Write-Host "everything will end up in Computer.log"

Stop-Transcript

1
这应该是公认的答案。它的本机和最小。
Nitin Badole

1
使用非常简单。我建议添加-AppendNoClobber以其他方式覆盖日志。另请注意,它会以标题的形式输出有关进程和主机的许多内容,因此它不直接等同于屏幕上的内容,除非您使用-UseMinimalHeaderetc参数。
scipilot


3

使用这个 Log-Entry框架:

脚本:

Function Main {
    Log -File "D:\Apps\Logs\$Env:computername.log"

    $tcp = (get-childitem c:\windows\system32\drivers\tcpip.sys).Versioninfo.ProductVersionRaw
    $dfs = (get-childitem C:\Windows\Microsoft.NET\Framework\v2.0.50727\dfsvc.exe).Versioninfo.ProductVersionRaw

    Log "TCPIP.sys Version on $computer is:" $tcp
    Log "DFSVC.exe Version on $computer is:" $dfs

    If (get-wmiobject win32_share | where-object {$_.Name -eq "REMINST"}) {Log "The REMINST share exists on $computer"}
    Else {Log "The REMINST share DOES NOT exist on $computer - Please create as per standards"}

    "KB2450944", "KB3150513", "KB3176935" | ForEach {
        $hotfix = Get-HotFix -Id $_ -ErrorAction SilentlyContinue
        If ($hotfix) {Log -Color Green Hotfix $_ is installed}
        Else {Log -Color Red Hotfix $_ " is NOT installed - Please ensure you install this hotfix"}
    }
}

屏幕输出: 屏幕输出

日志文件(位于D:\Apps\Logs\<computername>.log):

2017-05-31  Write-Log (version: 01.00.02, PowerShell version: 5.1.14393.1198)
19:19:29.00 C:\Users\User\PowerShell\Write-Log\Check.ps1 
19:19:29.47 TCPIP.sys Version on  is: {Major: 10, Minor: 0, Build: 14393, Revision: 1066, MajorRevision: 0, MinorRevision: 1066}
19:19:29.50 DFSVC.exe Version on  is: {Major: 2, Minor: 0, Build: 50727, Revision: 8745, MajorRevision: 0, MinorRevision: 8745}
19:19:29.60 The REMINST share DOES NOT exist on  - Please create as per standards
Error at 25,13: Cannot find the requested hotfix on the 'localhost' computer. Verify the input and run the command again.
19:19:33.41 Hotfix KB2450944 is NOT installed - Please ensure you install this hotfix
19:19:37.03 Hotfix KB3150513 is installed
19:19:40.77 Hotfix KB3176935 is installed
19:19:40.77 End

3
function WriteLog
{
    Param ([string]$LogString)
    $LogFile = "C:\$(gc env:computername).log"
    $DateTime = "[{0:MM/dd/yy} {0:HH:mm:ss}]" -f (Get-Date)
    $LogMessage = "$Datetime $LogString"
    Add-content $LogFile -value $LogMessage
}

WriteLog "This is my log message"

1

您可能只想使用新的TUN.Logging PowerShell模块,它也可以发送日志邮件。只需使用Start-Log和/或Start-MailLog cmdlet开始记录,然后仅使用Write-HostLog,Write-WarningLog,Write-VerboseLog,Write-ErrorLog等即可写入控制台和日志文件/邮件。然后在末尾调用Send-Log和/或Stop-Log,瞧,您的日志记录了。只需从PowerShell库通过安装

Install-Module -Name TUN.Logging

或者只是点击链接: https //www.powershellgallery.com/packages/TUN.Logging

该模块的文档可以在这里找到:https : //github.com/echalone/TUN/blob/master/PowerShell/Modules/TUN.Logging/TUN.Logging.md


0

我已经玩了一段时间了,我有一些对我来说很好的东西。日志文件的编号以“ 0”开头,但保留文件扩展名。我知道每个人都喜欢为所有功能创建函数,但是我开始删除执行一项简单任务的函数。少花招,为什么要用很多词?可能会删除其他功能,并可能在其他模块之外创建功能。我将记录器脚本保留在中央共享中,并在本地副本(如果已更改)中进行复制,或者在需要时从中央位置加载它。

首先,我导入记录器:

#Change directory to the script root
cd $PSScriptRoot

#Make a local copy if changed then Import logger
if(test-path "D:\Scripts\logger.ps1"){
    if (Test-Path "\\<server>\share\DCS\Scripts\logger.ps1") {
        if((Get-FileHash "\\<server>\share\DCS\Scripts\logger.ps1").Hash -ne (Get-FileHash "D:\Scripts\logger.ps1").Hash){
            rename-Item -path "..\logger.ps1" -newname "logger$(Get-Date -format 'yyyyMMdd-HH.mm.ss').ps1" -force
            Copy-Item "\\<server>\share\DCS\Scripts\logger.ps1" -destination "..\" -Force 
        }
    }
}else{
    Copy-Item "\\<server>\share\DCS\Scripts\logger.ps1" -destination "..\" -Force
}
. "..\logger.ps1"

定义日志文件:

$logfile = (get-location).path + "\Log\" + $QProfile.replace(" ","_") + "-$metricEnv-$ScriptName.log"

我记录的内容取决于我创建的调试级别:

if ($Debug -ge 1){
    $message = "<$pid>Debug:$Debug`-Adding tag `"MetricClass:temp`" to $host_name`:$metric_name"
    Write-Log $message $logfile "DEBUG"
}

在编码方面,我可能会觉得自己有点“ hack”,所以这可能不是最漂亮的,但这是我的版本logger.ps1

# all logging settins are here on top
param(
    [Parameter(Mandatory=$false)]
        [string]$logFile = "$(gc env:computername).log",
    [Parameter(Mandatory=$false)]
        [string]$logLevel = "DEBUG", # ("DEBUG","INFO","WARN","ERROR","FATAL")
    [Parameter(Mandatory=$false)]
        [int64]$logSize = 10mb,
    [Parameter(Mandatory=$false)]
        [int]$logCount = 25
) 
# end of settings

function Write-Log-Line ($line, $logFile) {
    $logFile | %{ 
           If (Test-Path -Path $_) { Get-Item $_ } 
           Else { New-Item -Path $_ -Force } 
    } | Add-Content -Value $Line -erroraction SilentlyCOntinue
}

function Roll-logFile
{
    #function checks to see if file in question is larger than the paramater specified if it is it will roll a log and delete the oldes log if there are more than x logs.
    param(
        [string]$fileName = (Get-Date).toString("yyyy/MM/dd HH:mm:ss")+".log", 
        [int64]$maxSize = $logSize, 
        [int]$maxCount = $logCount
    )
    $logRollStatus = $true
    if(test-path $filename) {
        $file = Get-ChildItem $filename
        # Start the log-roll if the file is big enough

        #Write-Log-Line "$Stamp INFO Log file size is $($file.length), max size $maxSize" $logFile
        #Write-Host "$Stamp INFO Log file size is $('{0:N0}' -f $file.length), max size $('{0:N0}' -f $maxSize)"
        if($file.length -ge $maxSize) {
            Write-Log-Line "$Stamp INFO Log file size $('{0:N0}' -f $file.length) is larger than max size $('{0:N0}' -f $maxSize). Rolling log file!" $logFile
            #Write-Host "$Stamp INFO Log file size $('{0:N0}' -f $file.length) is larger than max size $('{0:N0}' -f $maxSize). Rolling log file!"
            $fileDir = $file.Directory
            $fbase = $file.BaseName
            $fext = $file.Extension
            $fn = $file.name #this gets the name of the file we started with

            function refresh-log-files {
                 Get-ChildItem $filedir | ?{ $_.Extension -match "$fext" -and $_.name -like "$fbase*"} | Sort-Object lastwritetime
            }
            function fileByIndex($index) {
                $fileByIndex = $files | ?{($_.Name).split("-")[-1].trim("$fext") -eq $($index | % tostring 00)}
                #Write-Log-Line "LOGGER: fileByIndex = $fileByIndex" $logFile
                $fileByIndex
            }
            function getNumberOfFile($theFile) {
                $NumberOfFile = $theFile.Name.split("-")[-1].trim("$fext")
                if ($NumberOfFile -match '[a-z]'){
                    $NumberOfFile = "01"
                }
                #Write-Log-Line "LOGGER: GetNumberOfFile = $NumberOfFile" $logFile
                $NumberOfFile
            }

            refresh-log-files | %{
                [int32]$num = getNumberOfFile $_
                Write-Log-Line "LOGGER: checking log file number $num" $logFile
                if ([int32]$($num | % tostring 00) -ge $maxCount) {
                    write-host "Deleting files above log max count $maxCount : $_"
                    Write-Log-Line "LOGGER: Deleting files above log max count $maxCount : $_" $logFile
                    Remove-Item $_.fullName
                }
            }

            $files = @(refresh-log-files)

            # Now there should be at most $maxCount files, and the highest number is one less than count, unless there are badly named files, eg non-numbers
            for ($i = $files.count; $i -gt 0; $i--) {
                $newfilename = "$fbase-$($i | % tostring 00)$fext"
                #$newfilename = getFileNameByNumber ($i | % tostring 00) 
                if($i -gt 1) {
                    $fileToMove = fileByIndex($i-1)
                } else {
                    $fileToMove = $file
                }
                if (Test-Path $fileToMove.PSPath) { # If there are holes in sequence, file by index might not exist. The 'hole' will shift to next number, as files below hole are moved to fill it
                    write-host "moving '$fileToMove' => '$newfilename'"
                    #Write-Log-Line "LOGGER: moving $fileToMove => $newfilename" $logFile
                    # $fileToMove is a System.IO.FileInfo, but $newfilename is a string. Move-Item takes a string, so we need full path
                    Move-Item ($fileToMove.FullName) -Destination $fileDir\$newfilename -Force
                }
            }
        } else {
            $logRollStatus = $false
        }
    } else {
        $logrollStatus = $false
    }
    $LogRollStatus
}


Function Write-Log {
    [CmdletBinding()]
    Param(
    [Parameter(Mandatory=$True)]
    [string]
    $Message,

    [Parameter(Mandatory=$False)]
    [String]
    $logFile = "log-$(gc env:computername).log",

    [Parameter(Mandatory=$False)]
    [String]
    $Level = "INFO"
    )
    #Write-Host $logFile
    $levels = ("DEBUG","INFO","WARN","ERROR","FATAL")
    $logLevelPos = [array]::IndexOf($levels, $logLevel)
    $levelPos = [array]::IndexOf($levels, $Level)
    $Stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss:fff")

    # First roll the log if needed to null to avoid output
    $Null = @(
        Roll-logFile -fileName $logFile -filesize $logSize -logcount $logCount
    )

    if ($logLevelPos -lt 0){
        Write-Log-Line "$Stamp ERROR Wrong logLevel configuration [$logLevel]" $logFile
    }

    if ($levelPos -lt 0){
        Write-Log-Line "$Stamp ERROR Wrong log level parameter [$Level]" $logFile
    }

    # if level parameter is wrong or configuration is wrong I still want to see the 
    # message in log
    if ($levelPos -lt $logLevelPos -and $levelPos -ge 0 -and $logLevelPos -ge 0){
        return
    }

    $Line = "$Stamp $Level $Message"
    Write-Log-Line $Line $logFile
}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.