我有一个.ps1脚本,该脚本接收一些内部SQL数据并将其同步到Google API。
它通过对我们的数据运行foreach,使用逻辑生成API命令,然后通过System.IO.StreamWriter将这些命令写入文本文件来实现。然后,API处理器对该文件运行批处理作业。
我遇到的问题是,批处理作业部分似乎在foreach完成写入文件之前被触发,这会使整个脚本失败。
这是我的代码的简化版本:
$stream = [System.IO.StreamWriter] "C:\GAM\uploads\stream\gamBatch$today.txt";
## Loop csv and generate Google OU path
Write-Host "Generating location strings, OU paths, and update commands..."
Import-CSV "C:\uploads\Upload$today.csv" | ForEach-Object {
## Define fancy vars here
## Do fancy logic here
## Stream command list to log file
$line = "update $deviceId assetid $Barcode location $location ou $ouPath";
$stream.WriteLine($line);
};
## Trim top line of batch file (Removes header line)
(Get-Content "C:\uploads\stream\Batch$today.txt" | Select-Object -Skip 1) | Set-Content "C:\uploads\stream\Batch$today.txt";
## Close Stream instance and bulk run commands
Write-Host "Running batch command..."
$stream.WriteLine("commit-batch");
$stream.close();
apiBatch "C:\uploads\stream\Batch$today.txt";
这将在我的日志中生成此错误:
PS>TerminatingError(Set-Content): "The process cannot access the file
'C:\uploads\stream\Batch2020-05-14.txt' because it is being used by another process."
我如何在启动批处理命令之前让Powershell等待txt文件写入完成?
无需将第一行写入文件,仅需在之后立即将其再次删除(并且必须重写文件的其余部分)。
如果您在ForEach-Object
循环中对它没有做任何有意义的事情,请立即跳过它:
Import-CSV "C:\uploads\Upload$today.csv" | Select-Object -Skip 1 | ForEach-Object {
# ...
$stream.WriteLine($line)
}
如果需要检查ForEach-Object
主体内的第一行,请确保在第一次迭代中跳过调用WriteLine()
:
$first = $true
Import-CSV "C:\uploads\Upload$today.csv" | ForEach-Object {
# ...
if($first){
$first = $false
}
else{
$stream.WriteLine($line)
}
}
或者,在用StreamWriter
重写文件之前,先关闭Set-Content
,然后使用Add-Content
或新的流编写器来写最后一行:
Import-CSV "C:\uploads\Upload$today.csv" | ForEach-Object {
# ...
$stream.WriteLine($line)
}
# dispose of the current writer (will close the file stream)
$stream.Dispose()
... | Set-Content "C:\uploads\stream\Batch$today.txt"
# open a new writer and append the last string
$stream = (Get-Item "C:\uploads\stream\Batch$today.txt").AppendText()
$stream.WriteLine("commit-batch")
# or use `Add-Content`
"commit-batch" | Add-Content "C:\uploads\stream\Batch$today.txt"