简体   繁体   English

通过登录功能调用时出文件

[英]Out-File when calling through log through function

I am writing a script to copy all directories and items from one folder to another if they are more than seven days old. 我正在编写一个脚本,将超过7天的所有目录和项目从一个文件夹复制到另一个文件夹。

I created a function for writing to a log. 我创建了一个写入日志的函数。 I call the function when I want to write something to the log. 我想在日志中写入内容时调用该函数。 I am trying to list all items that I am copying. 我正在尝试列出我要复制的所有项目。 Normally when I do this I would call Out-File , but, again, this time I'm using a function. 通常,当我执行此操作时,我将调用Out-File ,但是再次,这次我使用的是函数。 I've tried numerous iterations of getting the directory listing to log. 我已经尝试了无数次迭代来获取目录列表进行记录。 It either doesn't log correctly (bad format), messes up the format of the rest of the log, or doesn't log at all for the directory listing. 它要么无法正确记录(格式错误),要么弄乱了其余日志的格式,或者根本不记录目录列表。 Can you please assist? 你能帮忙吗?

Basically, I want to write all directories or files greater than seven days old to my logfile. 基本上,我想将所有大于7天的目录或文件写入我的日志文件。 The lines that have an issue ends with Out-File $logfile -Append . 有问题的行以Out-File $logfile -Append I tried two different ways to get what I wanted. 我尝试了两种不同的方式来获得想要的东西。

$sourceDir = 'c:\temp\test\'
$targetDir = 'c:\temp\'
$date = (Get-Date).AddDays(-7)
$fileName = "TransfertoStream_"
$LogFile = "$($sourceDir)$($fileName)$(get-date -Format yyyyMMdd_HHmmss).log"

function LogWrite {
    Param ([string]$logstring)
    Add-Content $Logfile -Value $logstring
}
LogWrite "Created Log"

function Get-TimeStamp {
    return "[{0:MM/dd/yy} {0:HH:mm:ss}]" -f (Get-Date)
}

LogWrite "$(Get-Timestamp) Created Timestamp "
LogWrite "$(Get-Timestamp) looking for all files with a date modified older than $($date)"

if (dir $source | %{ dir $_.FullName | ?{ $_.LastWriteTime -lt $date }}) {
    LogWrite "$(Get-Timestamp) There are files to transfer"
    LogWrite "$(Get-Timestamp) Here are the files and directories I am working on today"

    Get-ChildItem -Path $sourceDir -Directory -Recurse -Force | % {
        dir $_.FullName | ?{ $_.LastWriteTime -lt $date }
    } | Out-File $LogFile -Append

    Get-ChildItem $sourceDir -Recurse | % {
        $dest = $targetDir + $_.FullName.SubString($sourceDir.Length)

        if (!($dest.Contains('.')) -and !(Test-Path $dest)) {
            mkdir $dest
        }

        Copy-Item $_.FullName -Destination $dest -Force | Out-File $logfile -Append
    }
} else {
    LogWrite "$(Get-TimeStamp) No files to transfer"
    LogWrite "$(Get-TimeStamp) Ending"
}

The log looks like this, all the information at the end should be on no more than two lines... 日志看起来像这样,最后的所有信息不应超过两行...

Created Log
[07/03/18 17:23:34] Created Timestamp 
[07/03/18 17:23:34] looking for all files with a date modified older than 06/26/2018 17:23:34
[07/03/18 17:23:34] There are files to transfer
[07/03/18 17:23:34] Here are the files and directories I am working on today




         D i r e c t o r y :   C : \ t e m p \ t e s t \ N e w   f o l d e r 





 M o d e                                 L a s t W r i t e T i m e                   L e n g t h   N a m e                                                                                                                                                                                                                                                                                   

 - - - -                                 - - - - - - - - - - - - -                   - - - - - -   - - - -                                                                                                                                                                                                                                                                                   

 - a - - - -                 9 / 1 9 / 2 0 1 4       6 : 4 1   A M                 8 8 4 7 9 8 2   0 6   S h a k e   I t   O f f   -   C o p y . m p 3                                                                                                                                                                                                                                       

Can you think of a cleaner/simpler/more elegant way to get the file listing? 您能想到一种更干净/更简单/更优雅的方法来获取文件列表吗?

You're mixing Add-Content and Out-File output, which use different default encodings. 您正在混合使用不同默认编码的Add-ContentOut-File输出。 The *-Content cmdlets default to ASCII¹, whereas the Out-File cmdlet defaults to Unicode (little endian UTF-16, to be precise). *-Content -Content cmdlet的默认值为ASCII¹,而Out-File cmdlet的默认值为Unicode(准确地说,是小端UTF-16)。 UTF-16 characters are encoded as 2 bytes, whereas ASCII characters are encoded as 1 byte. UTF-16字符编码为2个字节,而ASCII字符编码为1个字节。 Hence the gratuitious spacing in the output added by Out-File . 因此,由Out-File添加的输出中的多余间隔。

From the Out-File documentation : Out-File文档中

-Encoding

Specifies the type of character encoding used in the file. 指定文件中使用的字符编码的类型。 The acceptable values for this parameter are: 此参数的可接受值为:

[...] [...]

Unicode is the default. Unicode是默认设置。

From the Add-Content documentation : Add-Content文档中

-Encoding

Specifies the file encoding. 指定文件编码。 The default is ASCII. 默认值为ASCII。

You see the 2 bytes of the Unicode characters displayed as 2 characters because the file was originally created by Add-Content (using that cmdlet's default encoding). 您会看到Unicode字符的2个字节显示为2个字符,因为该文件最初是由Add-Content创建的(使用该cmdlet的默认编码)。 Had the file originally been created as a Unicode file and you wrote ASCII text to it afterwards then you'd see what is called "mojibake" (two ASCII characters being displayed as one Unicode character). 如果该文件最初是作为Unicode文件创建的,然后您向其中写入了ASCII文本,那么您将看到所谓的“ mojibake” (两个ASCII字符显示为一个Unicode字符)。 That normally shouldn't happen when appending to a Unicode file with Add-Content , though, because the cmdlet honors the BOM (Byte Order Mark) that indicates the encoding used for the file. 但是,当使用Add-Content附加到Unicode文件时,通常不会发生这种情况,因为cmdlet会使用BOM表 (字节顺序标记)来表示该文件所使用的编码。

The general recommendation is not to mix *-Content cmdlets with Out-File . 一般建议不要将*-Content cmdlet与Out-File混合使用。 Use one or the other, and stick with it. 使用一个或另一个,并坚持下去。 If for some reason you must use Out-File along with *-Content cmdlets enforce the desired encoding via the parameter -Encoding . 如果由于某些原因必须将Out-File*-Content cmdlet一起使用,则可以通过参数-Encoding强制执行所需的编码。

With that said, if you already have a logging function present: use it for all the logging. 话虽如此,如果您已经有了日志记录功能,请使用它进行所有日志记录。 Do not log some lines one way and others a different way. 不要以某种方式记录某些行,而以其他方式记录其他行。 Extend your logging function so that it accepts input from the pipeline: 扩展您的日志记录功能,以便它接受来自管道的输入:

function LogWrite {
    [CmdletBinding()]
    Param (
        [Parameter(Position=0, Mandatory=$false, ValueFromPipeline=$true)]
        [string]$logstring = ""
    )

    Process {
        $logstring | Add-Content $Logfile
    }
}

so that you can use it like this: 这样您就可以像这样使用它:

LogWrite "something"

or like this: 或像这样:

Get-ChildItem | LogWrite

or like this: 或像这样:

Get-ChildItem | Out-String | LogWrite

depending on the kind of log output you want to get. 取决于您要获取的日志输出的类型。

I would also recommend adding a timestamp inside the logging function rather than adding timestamps to individual strings: 我还建议在日志记录函数中添加时间戳,而不是将时间戳添加到各个字符串:

"$(Get-Timestamp) ${logstring}" | Add-Content $Logfile

¹ Yes, I am aware that technically the encoding is ANSI (or rather one of the many ANSI encodings), and that actual ASCII encoding uses 7 bits, not 8 bits like ANSI. ¹是的,我知道从技术上讲,编码是ANSI(或者是许多ANSI编码之一),实际的ASCII编码使用7位,而不是像ANSI那样的8位。 However, in the context of the question that is a distinction without a difference, because the problem at hand is the fact that UTF-16 characters are stored using 2 bytes per character, while ASCII and ANSI characters alike are stored using just one byte per character. 但是,在这个问题的区别中没有区别,因为当前的问题是每个字符使用2个字节存储UTF-16字符,而每个字符仅使用一个字节存储ASCII和ANSI字符。字符。

Here's a simple logging function that will accomplish what you want: 这是一个简单的日志记录功能,可以完成您想要的操作:

function Write-Log {
    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipeline)]
        [string] $Message,

        [string] $Path = "$sourceDir$fileName$(Get-Date -UFormat %Y%m%d_%H%M%S).log"
    )

    process {
        "$(Get-Date -UFormat '[%m/%d/%Y %H:%M:%S]') $Message" |
            Out-File -FilePath $Path -Append -Encoding UTF8 -Force
    }
}

In use: 正在使用:

Write-Log 'Created timestamp'
Write-Log "Looking for all files with a date modified older than $date"

if ($files = Get-ChildItem -Path $source | Get-ChildItem | Where-Object LastWriteTime -lt $date) {
    Write-Log 'There are files to transfer'
    Write-Log 'Here are the files and directories I am working on today'

    $files.FullName | Write-Log

    Get-ChildItem -Path $sourceDir -Recurse |
        ForEach-Object {
            $dest = $targetDir + $_.FullName.Substring($sourceDir.Length)

            if (-not $dest.Contains('.') -and -not (Test-Path -Path $dest)) {
                New-Item -Path $dest -ItemType Directory
            }

            Copy-Item -Path $_.FullName -Destination $dest -Force -PassThru |
                ForEach-Object FullName |
                Write-Log
        }
} else {
    Write-Log 'No files to transfer'
    Write-Log 'Ending'
}

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

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