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

时间:2018-07-03 21:36:39

标签: function powershell

我正在编写一个脚本,将超过7天的所有目录和项目从一个文件夹复制到另一个文件夹。

我创建了一个写入日志的函数。我想在日志中写入内容时调用该函数。我正在尝试列出我要复制的所有项目。通常,当我这样做时,我会调用df = pd.DataFrame(df.values[1:], columns=df.values[0]) print(df) Animal Mineral Vegetable 0 Bear Quartz Brocolli 1 Turtle Amethyst Asparagus ,但是,这次,我再次使用了一个函数。我已经尝试了无数次迭代来获取目录列表进行记录。它要么无法正确记录(格式错误),要么弄乱了其余日志的格式,或者根本不记录目录列表。你能帮忙吗?

基本上,我想将所有大于7天的目录或文件写入我的日志文件。有问题的行以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"
}

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

2 个答案:

答案 0 :(得分:4)

您正在混合使用不同默认编码的Add-ContentOut-File输出。 *-Content cmdlet的默认值为ASCII¹,而Out-File cmdlet的默认值为Unicode(准确地说是小尾数UTF-16)。 UTF-16字符编码为2个字节,而ASCII字符编码为1个字节。因此,Out-File添加的输出中的多余空格。

来自Out-File documentation

  

-Encoding

     

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

     

[...]

     

Unicode是默认设置。

来自Add-Content documentation

  

-Encoding

     

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

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

一般建议不要将*-Content cmdlet与Out-File混合使用。使用一个或另一个,并坚持下去。如果由于某些原因必须与Out-File一起使用*-Content cmdlet,则可以通过参数-Encoding强制执行所需的编码。

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

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

取决于要获取的日志输出的类型。

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

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

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

答案 1 :(得分:0)

这是一个简单的日志记录功能,可以完成您想要的操作:

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