如何在PowerShell中装饰现有功能或传递功能对象



我想保存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和相似的文件写入Fucntion使用完全相同的模式。有没有办法将Out-File命令作为参数传递给Out-Bak,以便我可以将函数用作输出命令的某种通用装饰器?

让备份函数仅执行其名称所建议的内容:备份文件。

  •  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 Parser之类的奥术物品:

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失败了,因为出于某种原因获得pscallstack将表达式返回为callee,现在我不知道获得父的调用上下文的其他方法。

最新更新