Function 通过log-through函数调用时输出文件

Function 通过log-through函数调用时输出文件,function,powershell,Function,Powershell,我正在编写一个脚本,将所有目录和项目从一个文件夹复制到另一个文件夹,如果它们超过七天 我创建了一个用于写入日志的函数。当我想在日志中写入内容时,我调用该函数。我正在尝试列出我正在复制的所有项目。通常,当我这样做时,我会调用Out File,但这次我使用的是一个函数。我已经尝试了无数次迭代来记录目录列表。它要么记录不正确(格式不正确),弄乱了其余日志的格式,要么根本不记录目录列表。你能帮忙吗 基本上,我想将所有超过七天的目录或文件写入日志文件。有问题的行以Out File$logfile-Appe

我正在编写一个脚本,将所有目录和项目从一个文件夹复制到另一个文件夹,如果它们超过七天

我创建了一个用于写入日志的函数。当我想在日志中写入内容时,我调用该函数。我正在尝试列出我正在复制的所有项目。通常,当我这样做时,我会调用
Out File
,但这次我使用的是一个函数。我已经尝试了无数次迭代来记录目录列表。它要么记录不正确(格式不正确),弄乱了其余日志的格式,要么根本不记录目录列表。你能帮忙吗

基本上,我想将所有超过七天的目录或文件写入日志文件。有问题的行以
Out File$logfile-Append
结尾。我尝试了两种不同的方法来得到我想要的

$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"
}
日志看起来是这样的,末尾的所有信息不应超过两行

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                                                                                                                                                                                                                                       

您能想出一种更干净/更简单/更优雅的方式来获取文件列表吗?

这里有一个简单的日志功能,它可以实现您想要的功能:

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
    }
}
使用中:

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'
}

下面是一个简单的日志功能,它将实现您想要的功能:

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
    }
}
使用中:

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'
}

您正在混合使用不同的默认编码的
添加内容
输出文件
输出。
*-Content
cmdlet默认为ASCII,而
Out File
cmdlet默认为Unicode(确切地说是little-endian UTF-16)。UTF-16字符编码为2字节,而ASCII字符编码为1字节。因此,
Out文件
在输出中添加了不必要的间距

从:

-编码

指定文件中使用的字符编码类型。此参数的可接受值为:

[……]

默认为Unicode。

从:

-编码

指定文件编码默认值为ASCII。

您会看到Unicode字符的2个字节显示为2个字符,因为文件最初是由
添加内容
创建的(使用该cmdlet的默认编码)。如果文件最初是作为Unicode文件创建的,然后向其写入ASCII文本,那么您将看到所称内容(两个ASCII字符显示为一个Unicode字符)。但是,在使用
添加内容
附加到Unicode文件时,通常不应该发生这种情况,因为cmdlet会使用指示文件所用编码的(字节顺序标记)

一般建议不要将
*-Content
cmdlet与
Out文件混用。使用其中一种,并坚持下去。如果出于某种原因,您必须使用
Out File
*-Content
cmdlet,通过参数
-encoding
强制执行所需的编码

话虽如此,如果您已经有了一个日志记录功能:将其用于所有日志记录。不要以一种方式记录某些行,而以另一种方式记录其他行。扩展日志功能,使其接受来自管道的输入:

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

    Process {
        $logstring | Add-Content $Logfile
    }
}
这样您就可以像这样使用它:

LogWrite "something"
Get-ChildItem | LogWrite
Get-ChildItem | Out-String | LogWrite
或者像这样:

LogWrite "something"
Get-ChildItem | LogWrite
Get-ChildItem | Out-String | LogWrite
或者像这样:

LogWrite "something"
Get-ChildItem | LogWrite
Get-ChildItem | Out-String | LogWrite
取决于您想要获得的日志输出类型

我还建议在日志函数中添加时间戳,而不是在单个字符串中添加时间戳:

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


是的,我知道从技术上讲编码是ANSI(或者更确切地说是许多ANSI编码之一),并且实际的ASCII编码使用7位,而不是像ANSI那样使用8位。然而,在问题的上下文中,这是一个没有区别的区别,因为当前的问题是,UTF-16字符的存储每个字符使用2个字节,而ASCII和ANSI字符的存储每个字符仅使用一个字节。

您混合了
添加内容
输出文件
输出,使用不同的默认编码。
*-Content
cmdlet默认为ASCII,而
Out File
cmdlet默认为Unicode(确切地说是little-endian UTF-16)。UTF-16字符编码为2字节,而ASCII字符编码为1字节。因此,
Out文件
在输出中添加了不必要的间距

从:

-编码

指定文件中使用的字符编码类型。此参数的可接受值为:

[……]

默认为Unicode。

从:

-编码

指定文件编码默认值为ASCII。

您会看到Unicode字符的2个字节显示为2个字符,因为文件最初是由
添加内容
创建的(使用该cmdlet的默认编码)。如果文件最初是作为Unicode文件创建的,然后向其写入ASCII文本,那么您将看到所称内容(两个ASCII字符显示为一个Unicode字符)。但是,在使用
添加内容
附加到Unicode文件时,通常不应该发生这种情况,因为cmdlet会使用指示文件所用编码的(字节顺序标记)

一般建议不要将
*-Content
cmdlet与
Out文件混用。使用其中一种,并坚持下去。如果出于某种原因,您必须使用
Out File
*-Content
cmdlet,通过参数
-encoding
强制执行所需的编码

话虽如此,如果您已经有了一个日志记录功能:将其用于所有日志记录。不要以一种方式记录某些行,而以另一种方式记录其他行。扩展日志功能,使其接受来自管道的输入:

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

    Process {
        $logstring | Add-Content $Logfile
    }
}
这样您就可以像这样使用它:

LogWrite "something"
Get-ChildItem | LogWrite
Get-ChildItem | Out-String | LogWrite
或者像这样:

LogWrite "something"
Get-ChildItem | LogWrite
Get-ChildItem | Out-String | LogWrite