Saya ingin menjalankan proses eksternal dan menangkap output perintah itu ke variabel di PowerShell. Saya sedang menggunakan ini:
$params = "/verify $pc /domain:hosp.uhhg.org"
start-process "netdom.exe" $params -WindowStyle Hidden -Wait
Saya telah mengkonfirmasi bahwa perintah sedang dieksekusi, tetapi saya perlu menangkap keluaran menjadi variabel. Ini berarti saya tidak dapat menggunakan -RedirectOutput karena ini hanya pengalihan ke file.
powershell
process
Adam Bertram
sumber
sumber
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.-Credential
parameterStart-Process
adalah suatu keharusan - tetapi hanya saat itu (dan jika Anda ingin menjalankan perintah di jendela terpisah). Dan orang harus menyadari keterbatasan yang tak terhindarkan dalam kasus itu: Tidak ada kemampuan untuk menangkap output, kecuali sebagai - non-interleaved - teks dalam file , melalui-RedirectStandardOutput
dan-RedirectStandardError
.Jawaban:
Sudahkah Anda mencoba:
$OutputVariable = (Shell command) | Out-String
sumber
Shell Command
dengan apa pun yang ingin Anda jalankan. Sesederhana itu.-i
opsi tanpa menentukan file output. Mengarahkan output menggunakan2>&1
seperti yang dijelaskan dalam beberapa jawaban lain adalah solusinya.Catatan: Perintah dalam pertanyaan menggunakan
Start-Process
, yang mencegah penangkapan langsung dari output program target. Secara umum, jangan gunakanStart-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 ):
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 :
Atau, jika
<command>
adalah cmdlet atau canggih fungsi, Anda dapat menggunakan parameter umum-OutVariable
/-ov
: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.
: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):
Namun, untuk perintah eksternal, yang berikut ini lebih mungkin berfungsi seperti yang diharapkan:
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 ke
Out-String
:$cmdOutput = <command> | Out-String
Mengarahkan stderr ke stdout dengan
2>&1
, sehingga juga menangkapnya sebagai bagian dari aliran kesuksesan, dilengkapi dengan peringatan :Untuk membuat
2>&1
penggabungan stdout dan stderr pada sumbernya , biarkancmd.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
memanggilcmd.exe
dengan perintah<command>
dan keluar setelah<command>
selesai.2>&1
, yang memastikan bahwa pengalihan diteruskancmd.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 untukcmd.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 oleh2>&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 dengan
Out-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 ..ToString()
metode untuk setiap objek output bukan pipa keOut-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 dengan
Write-Error
(sebagai bonus, jika output tidak ditangkap, ini menghasilkan output yang disisipkan dengan benar bahkan ketika mencetak ke konsol):sumber
<command>
, Anda tidak boleh menggabungkan executable dan argumennya dalam satu string; dengan doa melaluicmd /c
Anda dapat melakukannya, dan itu tergantung pada situasi apakah itu masuk akal atau tidak. Skenario mana yang Anda maksud, dan dapatkah Anda memberikan contoh minimal?+
operator; berikut ini juga berfungsi:cmd /c c:\mycommand.exe $Args '2>&1'
- PowerShell menangani melewatkan elemen$Args
sebagai string yang dipisahkan oleh spasi dalam kasus itu, fitur yang disebut splatting .'2>&1'
bagiannya, dan tidak tertutupi()
seperti yang banyak dilakukan oleh skrip.Jika Anda ingin mengarahkan output kesalahan juga, Anda harus melakukan:
Atau, jika nama program memiliki spasi di dalamnya:
sumber
Atau coba ini. Ini akan menangkap output ke variabel $ scriptOutput:
sumber
$scriptOutput = & "netdom.exe" $params
Contoh kehidupan nyata lainnya:
Perhatikan bahwa contoh ini mencakup lintasan (yang dimulai dengan variabel lingkungan). Perhatikan bahwa tanda kutip harus mengelilingi path dan file EXE, tetapi bukan parameternya!
Catatan: Jangan lupa
&
karakter di depan perintah, tetapi di luar tanda kutip.Output kesalahan juga dikumpulkan.
Butuh beberapa saat untuk membuat kombinasi ini berfungsi, jadi saya berpikir bahwa saya akan membagikannya.
sumber
Saya mencoba jawabannya, tetapi dalam kasus saya, saya tidak mendapatkan hasil mentah. Sebaliknya itu dikonversi ke pengecualian PowerShell.
Hasil mentah yang saya dapatkan:
sumber
Saya mendapat yang berikut ini untuk bekerja:
$ result memberi Anda yang dibutuhkan
sumber
Hal ini berhasil untuk saya:
sumber
Jika semua yang Anda coba lakukan adalah menangkap output dari suatu perintah, maka ini akan bekerja dengan baik.
Saya menggunakannya untuk mengubah waktu sistem, karena
[timezoneinfo]::local
selalu menghasilkan informasi yang sama, bahkan setelah Anda membuat perubahan pada sistem. Ini adalah satu-satunya cara saya dapat memvalidasi dan mencatat perubahan zona waktu:Berarti saya harus membuka sesi PowerShell baru untuk memuat ulang variabel sistem.
sumber