代码改变世界

Windows PowerShell 2.0之进程管理

2010-12-18 00:50 by @天行健中国元素, ... 阅读, ... 评论, 收藏, 编辑

进程在操作系统中用于处理数据和进程间的交换,PowerShell的进程和服务管理机制能分析进程信息,并且直接操作进程实例指向的对象。这样对象化的命令为用户在提取数据及修改状态方面提供了方便,管道命令的优点结合对象化的进程和服务可以简化复杂的命令。本文将讲解如何操作进程及其属性,包括启动和终止进程,以及查询并显示进程信息。

在PowerShell中所有与进程相关的操作均由5个cmdlet来实现,即Get-Process、Start-Process、Stop-Process、Debug-Process和Wait-Process。下例获取所有与Process相关的cmdlet的方法:

PS C:\> Get-Command -Noun Process

CommandType Name Definition

----------- ---- ----------

Cmdlet Debug-Process Debug-Process [-Name] <Strin...

Cmdlet Get-Process Get-Process [[-Name] <String...

Cmdlet Start-Process Start-Process [-FilePath] <S...

Cmdlet Stop-Process Stop-Process [-Id] <Int32[]>...

Cmdlet Wait-Process Wait-Process [-Name] <String...

1 获取进程列表

任务管理器是个强大的工具,但其仅提供了进程清单。PowerShell允许用户快速生成各种关于系统的报告,并可为管道传递所有信息。下例按照特定属性值排序所有进程并返回顶端的5个:

PS C:\> Get-Process | sort VM -Descending | select -First 5

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName

------- ------ ----- ----- ----- ------ -- -----------

1621 39 74556 12908 894 645.19 3360 JAVAW

383 19 40448 50784 559 195.64 2684 WINWORD

835 34 68928 92044 433 57.38 6912 explorer

1292 38 140732 7976 379 ...23.52 4620 msnmsgr

542 18 33008 1600 243 320.83 5080 mysql

其中有些程序占用了大量内存,但是并不是占用大量内存的程序就一定是导致系统变慢的直接原因。还需要分析更详细的数据才能得出结论,如下按照WS(Working Set)属性检查工作区:

PS C:\> Get-Process | sort WS -Descending | select -First 5

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName

------- ------ ----- ----- ----- ------ -- -----------

846 34 68940 92060 434 57.66 6912 explorer

384 19 40568 51488 561 212.33 2684 WINWORD

221 10 65320 44572 183 263.77 4612 AcroRd32

705 22 23340 23932 141 2,824.16 1236 mysql

1621 39 74472 20256 894 647.58 3360 JAVAW

如果怀疑由于颠簸(thrashing)使得机器速度变慢,则需要分别使用PM和NPM属性查看分页和未分页内存数。

-【提示】---------

颠簸是不执行任何处理的计算机活动,通常是因为内存或其他资源耗尽或有限而无法完成所要执行的操作。当这种情况发生时,程序通过操作系统发出请求。操作系统则试图释放其他程序中占用的资源,从而导致不能响应新的请求。在虚拟存储系统(使用页管理逻辑存储或内存的操作系统)中,颠簸即发生过度页请求操作的情况。

发生颠簸的系统被认为是一个运行非常慢或一个进入暂停状态的系统。

------------------

这样可以获取所有占用超过50MB物理内存的进程,这种类型的操作在PowerShell中频繁出现,所以PowerShell支持KB、MB和GB此类的数字单位后缀。下例为执行的操作:

PS C:\> Get-Process | where {$_.WS -ge 50MB}

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName

------- ------ ----- ----- ----- ------ -- -----------

839 34 68096 191316 434 60.00 6912 JAVAW

3062 32 61180 70812 237 88.36 7800 Mysql

396 20 39556 56200 569 303.36 2684 WINWORD

可以看到,当前系统由于Oracle数据库(Oracle使用Java虚拟机实现跨平台操作,这里的javaw即其进程)占用了大量的分页内存,所以导致系统运行速度变慢。

2 启动和停止进程

PowerShell中所有与进程相关的操作均通过调用.NET的System.Diagnostics.Process对象来实现,启动进程只需要键入可执行程序的文件名。为获取进程对象的实例句柄,以便后面对其进行操作,执行Get-Process命令:

PS C:\> notepad

PS C:\> Get-Process notepad

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName

------- ------ ----- ----- ----- ------ -- -----------

48 3 1668 4020 32 0.14 2400 notepad

如果已经启动了多个notepad实例,则获取对应的实例可以通过进程ID或StartTime属性,但是这并不是最安全的一种途径。如在启动Notepad之后,运行Get-Process cmdlet之前,计算机的其他用户启动了Notepad实例,则使用这种方法获取的刚刚启动的进程并不是所需。获取刚刚启动进程句柄的最安全方法是在启动时使用Process.Start()静态方法,它会返回最新启动的进程句柄,如:

PS C:\> $notepad = [Diagnostics.Process]::Start("notepad.exe")

PS C:\> $notepad

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName

------- ------ ----- ----- ----- ------ -- -----------

44 3 1632 4000 32 0.19 2564 notepad

如果不考虑操作过程中会丢失数据,则终止进程可以使用进程的Kill方法$notepad.Kill()或者传递进程实例给Stop-Process cmdlet杀死进程,如Get-Process notepad | Stop-Process。在不丢失数据的情况下,需要尝试调用CloseMainWindow方法通知进程在退出之前提示保存。如果已经保存,则直接终止该进程。下例尝试关闭Notepad窗口,等待5秒。如果没有保存,则退出时会提示保存;否则直接终止:

PS C:\> notepad

PS C:\> function KillNotepad()

>> {

>> $notepad = Get-Process notepad

>> echo "Trying to closee the process window..."

>> $messageSend = $notepad.CloseMainWindow()

>> sleep 5

>> if(!$notepad.HasExited)

>> {

>> echo "Forcing process termination."

>> Stop-Process -Input $notepad

>> }

>> else

>> {

>> echo "Process exited gracefully"

>> }

>> }

>>

PS C:\> killnotepad

Trying to closee the process window...

Process exited gracefully

在程序中,CloseMainWindow仅返回一个是否已经向目标进程发送关闭窗口信号的标志。为了判别进程是否成功退出,其中使用了HasExited属性。

3 进程及其窗口

用户不能直接与Windows交互并传递消息,但是对于来源于.NET命名空间System.Windows.Forms的脚本对象来说则可能,可以使用进程类对外开放的MainWindowTitle属性来区分相同程序的不同实例。如果要获取到所有Google搜索的浏览器窗口,则可通过获取窗口标题来实现:

PS C:\> Get-Process |where {$_.MainWindowTitle -Like "*google*"}

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName

------- ------ ----- ----- ----- ------ -- -----------

584 19 16680 26420 122 3.38 2140 iexplore

通常情况下,窗口标题包含文档名、文件名或者其他重要数据,这样可以使用MainWindowTitle属性作为窗体的标识符。

另外一个与用户界面相关的进程属性是Responding,如果程序响应用户输入,则可以通过这个属性获取所有挂起的进程并杀死。如果并不希望杀死所有挂起的无响应进程,则比较好的选择是获取挂起的进程并等待一段时间。如果仍然没有响应,则将其杀死,如:

PS C:\> function waitforkill()

>> {

>> $before = (Get-Process | where {$_.Responding -eq $false})

>> sleep 10

>> $after = (Get-Process | where {$_.Responding -eq $false})

>> if(($before -ne $null) -and ($after -ne $null))

>> {

>> diff $before $after -IncludeEqual |

>> where {$_.SildIndicator -eq "=="} |

>> foreach {$_.InputObject | Stop-Process}

>> }

>> }

>>

PS C:\> waitforkill

上例首先获取挂起的进程,等待10秒。再次获取,两次结果的交集集合即需要清除的僵死进程。需要强调的是-includeEqual选项用于比较集合之间的差异,并且校验SideIndicator值为“==”。整个语句的含义为对象在两边的集合中均存在,而且无法在10秒钟内恢复的进程则认为是僵死的进程。

4 获取进程依赖的库

进程模块指所有被载入进程内存空间中的DLL或者exe文件,PowerShell中的Process类有两个属性用于操作模块,即MainModule和Modules。主模块通常是启动进程的exe文件,模块集合包含所有被载入的动态链接库。

可以通过MainModule属性获取可执行文件的路径,如下例获取PowerShell的存放位置:

PS C:\> (Get-process powershell).MainModule.FileName

C:\WINDOWS\system32\WindowsPowerShell\v1.0\PowerShell.exe

可以使用Modules集合查找一个进程依赖的库,下例获取计算器依赖的库清单:

PS C:\> (Get-Process calc).Modules

Size(K) ModuleName FileName

------- ---------- --------

124 calc.exe C:\WINDOWS\sys...

588 ntdll.dll C:\WINDOWS\sys...

1144 kernel32.dll C:\WINDOWS\sys...

……

用户通过特定的库可以了解程序如何工作,PowerShell甚至允许用户生成多种特定报告以发现类似的程序。如所有使用mscoree.dll的程序是.NET进程,下例获取使用动态库的进程清单:

PS C:\> Get-Process | foreach { $proc = $_;$proc.Modules|

>> where { $_.ModuleName -eq "mscoree.dll"} |

>> foreach {echo $proc}

>> }

>>

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName

------- ------ ----- ----- ----- ------ -- -----------

778 18 21576 27624 146 599.81 424 explorer

813 27 27144 37196 151 3,525.66 1236 explorer

916 34 72660 60356 439 189.63 6912 FetionFx

1555 29 80752 66632 276 838.36 2140 iexplore

793 6 28448 19324 146 10.09 4060 powershell

上例中的第1个foreach遍历调用所有的进程并获取所有模块,然后将所有的进程对象保存在$proc缓存变量中,最后用where cmdlet从进程清单中获取包含mscoree.dll模块;第2个foreach输出所有满足条件的进程。

5 获取程序发布的相关信息

读者可能有过发现可疑名称的进程,最后被确认为间谍程序或是病毒的经历。如果能正常地使用杀毒软件并经常升级,也许能避免这些情况的发生。除此以外,可以检查进程属性包含公司、产品和产品版本的返回值。尽管这些内容也有可能被恶意用户假造,但还是可以在一定范围内校验程序的来源。如果要确保程序的合法性和完整性,可以通过程序的数字签名来保证。

下例获取当前计算机中部分运行程序的发布信息清单:

PS C:\PowerShell> Get-Process |select Company,Product,ProductVersion |format-tab

le

Company Product ProductVersion

------- ------- --------------

Adobe Systems Incorporated Adobe Reader 7.0.5.2005092300

Microsoft Corporation Microsoft® Windows® Ope... 5.1.2600.5512

ASUSTeK Computer Inc. AsAcpiSvr.exe 5, 1, 1, 3012

ASUSTeK Computer Inc. AsEPCMon 5, 1, 1, 1002

ASUSTeK Computer Inc. AsTray 5, 1, 1, 3015

Broadcom Corporation. Bluetooth Software 5.5.0.3200

Microsoft Corporation Microsoft(R) Windows(R)... 5.1.2600.0

Microsoft Corporation Microsoft® Windows® Ope... 5.1.2600.5512

6 设置进程优先级

提高或降低程序运行的优先级是很常见的任务。当安装大型程序时,可能时间会比较长。很多用户可能会在安装文件的同时执行其他操作,这时就可以把安装的优先级降低,使其他程序正常运行。如果此时不执行其他操作,则可以把安装程序的优先级提高,使安装尽快完成。

在PowerShell中通过设置PriorityClass枚举属性来改变进程优先级,可通过传递类似 “BelowNormal”及“Normal”等字符串来实现。下例降低安装程序msiexec.exe的优先级:

PS C:\PowerShell> function LowerPriority()

>> {

>> echo "Lowering installer process priorities"

>> Get-Process msiexec -ErrorAction Stop |

>> foreach {$_.PriorityClass = "BelowNormal"}

>> Read-Host -Prompt "Press Enter to restore install priorities"

>> Get-Process msiexec -ErrorAction SilentlyContinue |

>> foreach { $_.PriorityClass = "Normal"}

>> }

>>

PS C:\PowerShell> Lowerpriority

执行上述脚本后会重新导入程序优先级到Normal级别。如果不存在运行的msiexec.exe进程,则希望脚本执行失败。而当等待安装完成后忽略所有错误,这种情况下使用ErrorAction参数。需要强调的是安装程序需要管理员权限,因此必须在管理员账户下执行上述脚本。

7 总 结

进程在操作系统中用于处理数据和进程间的交换,PowerShell的进程和服务管理机制能分析进程信息,并且直接操作进程实例指向的对象。本文讲述了如何使用PowerShell统一访问进程的方法并创建在PowerShell中操作进程的环境,这是系统管理自动化的重要步骤。

 

作者: 付海军
出处:http://blog.csdn.net/fuhj02
版权:本文版权归作者和csdn共有
转载:欢迎转载,为了保存作者的创作热情,请按要求【转载】,谢谢
要求:未经作者同意,必须保留此段声明;必须在文章中给出原文连接;否则必究法律责任
个人网站: http://txj.shell.tor.hu/