Catatan: Perintah dalam pertanyaan menggunakan Start-Process
, yang mencegah penangkapan langsung dari output program target. Secara umum, jangan gunakan Start-Process
untuk menjalankan aplikasi konsol secara sinkron - cukup panggil secara langsung , seperti pada shell apa pun. Dengan melakukan hal itu, aplikasi tetap terhubung ke stream standar konsol pemanggil, sehingga outputnya dapat ditangkap dengan penugasan sederhana $output = netdom ...
, sebagaimana dirinci di bawah ini.
Pada dasarnya , menangkap output dari utilitas eksternal bekerja sama dengan perintah-perintah asli PowerShell (Anda mungkin ingin penyegaran tentang cara menjalankan alat eksternal ):
$cmdOutput = <command> # captures the command's success stream / stdout
Catatan yang $cmdOutput
menerima array objek jika <command>
menghasilkan lebih dari 1 objek output , yang dalam kasus program eksternal berarti array string yang berisi jalur output program .
Jika Anda ingin $cmdOutput
selalu menerima string tunggal - berpotensi multi-garis - , gunakan
$cmdOutput = <command> | Out-String
Untuk menangkap output dalam variabel dan mencetak ke layar :
<command> | Tee-Object -Variable cmdOutput # Note how the var name is NOT $-prefixed
Atau, jika <command>
adalah cmdlet atau canggih fungsi, Anda dapat menggunakan parameter umum
-OutVariable
/-ov
:
<command> -OutVariable cmdOutput # cmdlets and advanced functions only
Perhatikan bahwa dengan -OutVariable
, tidak seperti dalam skenario lain, $cmdOutput
adalah selalu sebuah koleksi , bahkan jika hanya satu objek adalah output. Secara khusus, sebuah instance dari [System.Collections.ArrayList]
tipe seperti array dikembalikan.
Lihat masalah GitHub ini untuk diskusi tentang perbedaan ini.
Untuk menangkap output dari beberapa perintah , gunakan subekspresi ( $(...)
) atau panggil blok skrip ( { ... }
) dengan &
atau .
:
$cmdOutput = $(<command>; ...) # subexpression
$cmdOutput = & {<command>; ...} # script block with & - creates child scope for vars.
$cmdOutput = . {<command>; ...} # script block with . - no child scope
Perhatikan bahwa kebutuhan umum untuk awalan dengan &
(operator call) perintah individu yang nama / path dikutip - misalnya, $cmdOutput = & 'netdom.exe' ...
- tidak berhubungan dengan program eksternal per se (sama-sama berlaku untuk script PowerShell), tetapi sebuah sintaks persyaratan : PowerShell mem-parsing pernyataan yang dimulai dengan string yang dikutip dalam mode ekspresi secara default, sedangkan mode argumen diperlukan untuk menjalankan perintah (cmdlet, program eksternal, fungsi, alias), yang merupakan &
jaminan.
Perbedaan utama antara $(...)
dan & { ... }
/ . { ... }
adalah bahwa yang pertama mengumpulkan semua input dalam memori sebelum mengembalikannya secara keseluruhan, sedangkan yang terakhir mengalirkan output, cocok untuk pemrosesan pipa satu-per-satu.
Pengalihan juga berfungsi sama, secara mendasar (tetapi lihat peringatan di bawah):
$cmdOutput = <command> 2>&1 # redirect error stream (2) to success stream (1)
Namun, untuk perintah eksternal, yang berikut ini lebih mungkin berfungsi seperti yang diharapkan:
$cmdOutput = cmd /c <command> '2>&1' # Let cmd.exe handle redirection - see below.
Pertimbangan khusus untuk program eksternal :
Program eksternal , karena mereka beroperasi di luar sistem tipe PowerShell, hanya pernah mengembalikan string melalui aliran kesuksesan mereka (stdout).
Jika output berisi lebih dari 1 baris , PowerShell secara default membaginya menjadi array string . Lebih tepatnya, garis keluaran disimpan dalam larik tipe [System.Object[]]
yang elemennya adalah string ( [System.String]
).
Jika Anda ingin output menjadi string tunggal , berpotensi multi-line , pipa keOut-String
:
$cmdOutput = <command> | Out-String
Mengarahkan stderr ke stdout dengan2>&1
, sehingga juga menangkapnya sebagai bagian dari aliran kesuksesan, dilengkapi dengan peringatan :
Untuk membuat 2>&1
penggabungan stdout dan stderr pada sumbernya , biarkan cmd.exe
menangani pengalihan , menggunakan idiom berikut:
$cmdOutput = cmd /c <command> '2>&1' # *array* of strings (typically)
$cmdOutput = cmd /c <command> '2>&1' | Out-String # single string
cmd /c
memanggil cmd.exe
dengan perintah <command>
dan keluar setelah <command>
selesai.
- Perhatikan tanda kutip tunggal di sekitar
2>&1
, yang memastikan bahwa pengalihan diteruskan cmd.exe
daripada ditafsirkan oleh PowerShell.
Perhatikan bahwa melibatkan cmd.exe
berarti bahwa yang aturan untuk melarikan diri karakter dan memperluas variabel lingkungan ikut bermain, secara default di samping persyaratan PowerShell sendiri; di PS v3 + Anda dapat menggunakan parameter khusus --%
(yang disebut simbol stop-parsing ) untuk mematikan interpretasi parameter yang tersisa oleh PowerShell, kecuali untuk cmd.exe
referensi variabel-lingkungan-gaya seperti %PATH%
.
Perhatikan bahwa karena Anda menggabungkan stdout dan stderr pada sumber dengan pendekatan ini, Anda tidak akan dapat membedakan antara baris yang berasal dari stdout dan yang berasal dari stderr di PowerShell; jika Anda memang membutuhkan perbedaan ini, gunakan 2>&1
pengalihan PowerShell sendiri - lihat di bawah.
Gunakan pengalihan PowerShell 2>&1
untuk mengetahui baris mana yang berasal dari aliran apa :
Stderr output ditangkap sebagai catatan error ( [System.Management.Automation.ErrorRecord]
), bukan string, sehingga output array mungkin berisi campuran dari string (masing-masing string yang mewakili garis stdout) dan catatan error (setiap record mewakili garis stderr) . Perhatikan bahwa, seperti yang diminta oleh 2>&1
, string dan catatan kesalahan diterima melalui aliran output sukses PowerShell ).
Di konsol, catatan kesalahan dicetak dengan warna merah , dan yang pertama secara default menghasilkan tampilan multi-baris , dalam format yang sama dengan yang ditampilkan oleh kesalahan non-terminasi cmdlet; catatan kesalahan selanjutnya mencetak dengan warna merah juga, tetapi hanya mencetak pesan kesalahan mereka , pada satu baris .
Ketika keluaran ke konsol , senar biasanya datang pertama dalam array output, diikuti oleh catatan kesalahan (setidaknya di antara batch stdout / garis stderr output "pada saat yang sama"), tapi, untungnya, ketika Anda menangkap output , itu disisipkan dengan benar , menggunakan urutan output yang sama Anda akan dapatkan tanpa 2>&1
; dengan kata lain: saat mengeluarkan ke konsol , keluaran yang ditangkap TIDAK mencerminkan urutan di mana garis stdout dan stderr dihasilkan oleh perintah eksternal.
Jika Anda menangkap seluruh output dalam satu string denganOut-String
, PowerShell akan menambahkan baris tambahan , karena representasi string dari catatan kesalahan berisi informasi tambahan seperti lokasi ( At line:...
) dan kategori ( + CategoryInfo ...
); anehnya, ini hanya berlaku untuk catatan kesalahan pertama .
- Untuk bekerja di sekitar masalah ini, menerapkan
.ToString()
metode untuk setiap objek output bukan pipa ke Out-String
:
$cmdOutput = <command> 2>&1 | % { $_.ToString() }
;
di PS v3 + Anda dapat menyederhanakan untuk:
$cmdOutput = <command> 2>&1 | % ToString
(Sebagai bonus, jika output tidak ditangkap, ini menghasilkan output yang disisipkan dengan benar bahkan ketika mencetak ke konsol.)
Atau, filter catatan kesalahan keluar dan kirim ke aliran kesalahan PowerShell denganWrite-Error
(sebagai bonus, jika output tidak ditangkap, ini menghasilkan output yang disisipkan dengan benar bahkan ketika mencetak ke konsol):
$cmdOutput = <command> 2>&1 | ForEach-Object {
if ($_ -is [System.Management.Automation.ErrorRecord]) {
Write-Error $_
} else {
$_
}
}
Start-Process
untuk menjalankan aplikasi konsol (secara eksternal) secara sinkron - cukup panggil mereka secara langsung , seperti pada shell apa pun; yakni:netdom /verify $pc /domain:hosp.uhhg.org
. Dengan melakukan hal itu, aplikasi tetap terhubung ke stream standar konsol pemanggil, sehingga hasilnya dapat ditangkap dengan penugasan sederhana$output = netdom ...
. Sebagian besar jawaban yang diberikan di bawah ini secara implisit dilupakanStart-Process
demi eksekusi langsung.