Saya memiliki skrip .ps1 yang mengambil beberapa data SQL internal kami dan menyinkronkannya ke Google API.

Ini dilakukan dengan menjalankan foreach terhadap data kita, menggunakan logika untuk menghasilkan perintah API, dan menulis perintah tersebut ke file teks melalui System.IO.StreamWriter. Kemudian prosesor API menjalankan tugas batch pada file.

Masalah yang saya alami adalah bahwa bagian pekerjaan batch tampaknya diaktifkan sebelum foreach selesai menulis ke file, yang membuat seluruh skrip gagal.

Ini adalah versi sederhana dari kode saya:

$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";

Ini menghasilkan kesalahan ini di log saya:

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."

Bagaimana saya bisa membuat Powershell menunggu file txt selesai ditulis sebelum menjalankan perintah batch?

0
Jensen010 14 Mei 2020, 21:25

1 menjawab

Jawaban Terbaik

Tidak perlu menulis baris pertama ke file, hanya untuk kemudian menghapusnya lagi segera setelahnya (dan harus menulis ulang sisa file).

Jika Anda tidak melakukan sesuatu yang berarti dengannya di dalam loop ForEach-Object, lewati segera:

Import-CSV "C:\uploads\Upload$today.csv" | Select-Object -Skip 1 | ForEach-Object {
    # ...
    $stream.WriteLine($line)
}

Jika Anda perlu memeriksa baris pertama di dalam badan ForEach-Object, pastikan Anda melewatkan pemanggilan WriteLine() pada iterasi pertama:

$first = $true
Import-CSV "C:\uploads\Upload$today.csv" | ForEach-Object {
    # ...
    if($first){
        $first = $false
    }
    else{
        $stream.WriteLine($line)
    }
}

Atau, tutup StreamWriter sebelum menulis ulang file dengan Set-Content, lalu gunakan Add-Content, atau penulis aliran baru untuk menulis baris terakhir:

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"
1
Mathias R. Jessen 14 Mei 2020, 18:59