2012-01-12 29 views
19

Trợ giúp của Noob. Tôi đang cố gắng viết một kịch bản sẽ kiểm tra xem một tiến trình có đang chạy hay không, và nếu không, hãy bắt đầu nó. Nếu quá trình đang chạy, nó sẽ không làm gì cả. Tôi đã đưa ra những điều sau đây cho đến nay nhưng nó đang bắt đầu một thể hiện mới của quá trình bất kể nó đã chạy chưa. Bất kỳ trợ giúp được đánh giá cao.Powershell - nếu quy trình không chạy, hãy bắt đầu

$Prog = "C:\utilities\prog.exe" 
$Running = Get-Process prog -ErrorAction SilentlyContinue 
$Start = ([wmiclass]"win32_process").Create($Prog) 
if($Running -eq $null) 
{$Start} 
else 
{} 

Trả lời

24

Trước hết, đây là những gì sai trong mã của bạn. Trong code của bạn, quá trình này được tạo ra trước khi bạn đánh giá xem chương trình của bạn vẫn đang chạy

$Prog = "C:\utilities\prog.exe" 
$Running = Get-Process prog -ErrorAction SilentlyContinue 
$Start = ([wmiclass]"win32_process").Create($Prog) # the process is created on this line 
if($Running -eq $null) # evaluating if the program is running 
{$Start} 

Có thể tạo ra một khối mã cần được đánh giá thêm trong mã của bạn bằng cách gói nó trong {} (một scriptblock):

$Prog = "C:\utilities\prog.exe" 
$Running = Get-Process prog -ErrorAction SilentlyContinue 
$Start = {([wmiclass]"win32_process").Create($Prog)} 
if($Running -eq $null) # evaluating if the program is running 
{& $Start} # the process is created on this line 

Tuy nhiên, nếu bạn đang tìm kiếm một ngắn một lót để giải quyết vấn đề của bạn:

if (! (ps | ? {$_.path -eq $prog})) {& $prog} 
+0

OK cảm ơn bạn đã giải thích rõ ràng. – Charlotte

+0

Tôi không hiểu giải pháp của bạn sẽ giải quyết vấn đề như thế nào. Dòng '$ Start = ...' sẽ vẫn bắt đầu quá trình này mỗi lần. Tôi kiểm tra chạy mã và bội số của quá trình tương tự đã được bắt đầu. (hãy chắc chắn để kiểm tra với một chương trình cho phép một số instanses của chính nó) – LosManos

+0

Hi @LosManos, là nó có thể bạn quên {} (scriptblock)? –

3
$path = "C:\utilities\prog.exe"   
$list = get-process | where-object {$_.Path -eq $path }  
if ($list -eq $null) { start-process -filepath $path } 

Hoặc

$path = "C:\utilities\prog.exe" 
get-process | where-object {$_.Path -eq $path } | measure-object | where-object { $_.Count -eq 0} | foreach-object {start-process -filepath $path } 

Điều này sẽ giúp bạn tiết kiệm câu lệnh if và một khai báo biến. Nó có thể là một lệnh một dòng cũng như:

  1. Nhận xử lý
  2. Pick là những người có đường dẫn mà bạn quan tâm đến
  3. đối tượng sử dụng biện pháp để có được những số liệu thống kê về danh sách các bạn có
  4. Tiếp tục các đường ống chỉ khi giá trị đếm số liệu thống kê là 0
  5. quá trình Bắt đầu

Đừng để những foreach ở cuối đưa bạn đi. Đối tượng đo lường sẽ chỉ trả lại một mục, nơi sẽ trả về một hoặc không. Foreach chỉ được sử dụng để thực thi nếu kết quả bằng không. Nó sẽ không bắt đầu nhiều hơn sau đó một quá trình. :)

+1

Không cần phải sử dụng số đo/đếm. Giá trị 0 được coi là $ false, khác 0 là $ true. Nhìn vào cuối câu trả lời của jon-z để thực hiện thực tế. – x0n

+0

Bạn nói đúng. Cảm ơn cho tip; Tôi đã học được điều gì đó mới mẻ. Ví dụ cuối cùng của jon-z có vẻ là đẹp nhất. –

9

Trong Get-Process cmdlet, đối số tên quy trình phải là tên của tệp thi hành mà không có phần mở rộng tệp. Thử thay thế $Prog = "C:\utilities\prog.exe" bằng $Prog = "prog".

Theo ý kiến ​​của tôi, tập lệnh của bạn sẽ dễ đọc hơn nếu bạn lọc quá trình ra using the Where-Object cmdlet thay thế. Dưới đây là một ví dụ:

$programName = "prog" 
$isRunning = (Get-Process | Where-Object { $_.Name -eq $programName }).Count -gt 0 

if ($isRunning) 
# ... 
else 
# ... 

Bằng cách đó bạn có thể thoát khỏi những tranh cãi -ErrorAction SilentlyContinue, mà có thể gây nhầm lẫn cho người không phải là nhận thức được thực tế là Get-Processném một lỗi nếu nó không thể tìm thấy một quá trình với tên được chỉ định.

+0

OK Tôi đã không nghĩ đến việc làm theo cách đó, cảm ơn! – Charlotte

+0

+1 vì sai lầm của tôi dẫn tôi đến đây là tôi đã bao gồm phần mở rộng. – rbwhitaker

5

Hãy nhớ rằng PowerShell xử lý các đối tượng chứ không phải chỉ văn bản. Trong khi trong các tập tin batch bình thường bạn có thể thiết lập một biến thành một chuỗi và sau đó chỉ cần sử dụng nó như một lệnh:

set Foo=dir /b 
%Foo% 

... điều này không làm việc trong PowerShell.Do đó, nhiệm vụ của bạn là $Start đã tạo quy trình mới kể từ khi lệnh sau khi = được chạy và kết quả của nó được gán cho $Start.

Hơn nữa, bạn đang làm phức tạp những thứ không cần thiết. Tôi muốn đề nghị sau đây thay vì:

$Running = Get-Process prog -ErrorAction SilentlyContinue 
if (!$Running) { Start-Process C:\utilities\prog.exe } 

Kể từ Get-Process lợi nhuận một đối tượng (trong đó đánh giá để $true) hoặc $null (mà đánh giá để $false), bạn có thể đơn giản hóa việc kiểm tra như trình bày ở trên. Điều này được gọi là loại cưỡng chế, vì tuyên bố if dự kiến ​​giá trị boolean và các quy tắc về những gì sẽ được coi là $true$false rất nhất quán trong các trường hợp như trên. Và nó đẹp hơn.

Tôi cũng đã sử dụng lệnh ghép ngắn Start-Process thay vì WMI để tạo quy trình mới. Bạn thậm chí có thể sử dụng như sau:

if (!$Running) { C:\utilities\prog.exe } 

nếu ứng dụng không phải là một ứng dụng giao diện điều khiển (và do đó sẽ ngăn chặn kịch bản PowerShell cho đến khi nó thoát). PowerShell vẫn là một trình bao, vì vậy các chương trình bắt đầu là một cái gì đó hoạt động rất tốt :-)

Bạn thậm chí có thể thay đổi biến số $running, nhưng tôi đoán là một nhận xét sẽ làm rõ những gì bạn làm.

+0

Bạn đã đề cập đến các quy tắc đúng/sai ... Một bài đăng nhỏ để giúp chúng hiểu được Jeffrey có thể được tìm thấy tại đây (http://blogs.msdn.com/b/powershell/archive/2006/12/24/ boolean-values-and-operator.aspx). –

+0

Tôi nghĩ phần khó hiểu nhất là quy tắc với mảng một phần tử, nhưng chúng có ý nghĩa nếu bạn xem xét những thứ như '@ (...)' và do đó hoạt động như mong đợi vô hạn :-) – Joey

Các vấn đề liên quan