假设我想将Powershell命令的输出保存到文件中。我会像ls | out-file "path.txt"
那样做。我每天拨打几次这个电话,我担心函数调用(在这种情况下为ls
)会产生破坏我文件的错误数据。我觉得我需要备份!
对我来说,下一步是装饰out-file
调用,以便它自动将数据备份到单独的文件中。每天一次备份就足够了。这可以通过下面的自定义out-bak
功能来实现。突然,我使用ls | Out-Bak "path.txt"
进行自动备份。
function Out-Bak {
[cmdletbinding()]
Param (
[parameter(ValueFromPipeline)]
[string]$inputObject,
[parameter(Mandatory=$false)]
[string]$myPath
)
Begin {
$backupPath = [System.IO.Path]::ChangeExtension($myPath,".bak_$([DateTime]::Now.ToShortDateString())")
Remove-Item $myPath
Remove-Item $backupPath
}
Process {
Out-File -InputObject $input -FilePath $myPath -Append
Out-File -InputObject $input -FilePath $backupPath -Append
}
}
这解决了我的问题,但我希望能够对Out-csv
和类似的文件写入功能使用完全相同的模式。有没有办法将Out-File
命令作为参数传递给Out-Bak
,以便我可以将该函数用作输出命令的通用装饰器?
答案 0 :(得分:2)
让备份功能只做它的名字:备份文件。
ls | Out-File $path | Backup
........ | Out-File foo.txt | Backup
........ | Out-File -FilePath "$path\$name" | Backup
........ | Export-Csv -NoTypeInformation bar.csv | Backup
管道完成后,backup
cmdlet将简单地复制文件
要从先前的管道命令中找到文件路径,我们必须使用诸如AST解析器之类的神秘内容:
function Backup {
end {
$bakCmdText = (Get-PSCallStack)[1].Position.text
$bakCmd = [ScriptBlock]::Create($bakCmdText).
Ast.EndBlock.Statements[0].PipelineElements[-2].CommandElements
$bakParamInfo = if (!$bakCmd) { @{} }
else { @{} + (Get-Command ($bakCmd[0].value)).Parameters }
$bakSource = ''; $bakLiteral = $false; $bakPos = 0
while (!$bakSource -and ++$bakPos -lt $bakCmd.count) {
$bakToken = $bakCmd[$bakPos]
if ($bakToken.ParameterName) {
if ($bakToken.ParameterName -match '^(File|Literal)?Path$') {
$bakLiteral = $bakToken.ParameterName -eq 'LiteralPath'
} elseif (!$bakParamInfo[$bakToken.ParameterName].SwitchParameter) {
$bakPos++
}
continue
}
$bakSource = if ($bakToken.StringConstantType -in 'SingleQuoted', 'BareWord') {
$bakToken.value
} else {
[ScriptBlock]::Create($bakToken.extent.text).
InvokeWithContext(@{}, (Get-Variable bak* -scope 1))
}
}
if (!$bakSource) {
Write-Warning "Could not find file path in pipeline emitter: $bakCmdText"
return
}
$backupTarget = "$bakSource" + '.' + [DateTime]::Now.ToShortDateString() + '.bak'
$bakParams = @{ $(if ($bakLiteral) {'LiteralPath'} else {'Path'}) = "$bakSource" }
copy @bakParams -destination $backupTarget -Force
}
}
警告:它与$()
... | out-file "$($path)" | backup
失败,因为Get-PSCallStack由于某种原因返回表达式内容作为被调用者,现在我不知道获取父调用上下文的其他方法