我正在编写一个脚本,将超过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"
}
您能想到一种更干净/更简单/更优雅的方式来获取文件列表吗?
答案 0 :(得分:4)
您正在混合使用不同默认编码的Add-Content
和Out-File
输出。 *-Content
cmdlet的默认值为ASCII¹,而Out-File
cmdlet的默认值为Unicode(准确地说是小尾数UTF-16)。 UTF-16字符编码为2个字节,而ASCII字符编码为1个字节。因此,Out-File
添加的输出中的多余空格。
-Encoding
指定文件中使用的字符编码的类型。此参数可接受的值为:
[...]
Unicode是默认设置。
-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'
}