使用powershell管理进程和服务(翻译自官方文档7.1 M
01.使用process cmdlet管理进程
001.获取进程信息(Get-Process)
使用这个命令可以获得进程信息,你也可以指定名字或者进程id来指定获取信息的进程。
PS> Get-Process -id 0
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
0 0 0 16 0 0 Idle
指定属性的时候,如果找不到会报错。
如果指定名字,可以指定多个,并且支持通配符
PS> Get-Process -Name ex*
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
234 7 5572 12484 134 2.98 1684 EXCEL
555 15 34500 12384 134 105.25 728 explorer
更复杂一些的命令是加上机器名,并且用规范的格式输出
PS> Get-Process powershell -ComputerName localhost, Server01, Server02 |
Format-Table -Property Handles,
@{Label="NPM(K)";Expression={[int]($_.NPM/1024)}},
@{Label="PM(K)";Expression={[int]($_.PM/1024)}},
@{Label="WS(K)";Expression={[int]($_.WS/1024)}},
@{Label="VM(M)";Expression={[int]($_.VM/1MB)}},
@{Label="CPU(s)";Expression={if ($_.CPU -ne $()){$_.CPU.ToString("N")}}},
Id, ProcessName, MachineName -auto
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName MachineName
------- ------ ----- ----- ----- ------ -- ----------- -----------
258 8 29772 38636 130 3700 powershell Server01
398 24 75988 76800 572 5816 powershell localhost
605 9 30668 29800 155 7.11 3052 powershell Server02
002.终结进程 (Stop-Process)
可以使用名字来终结进程。
PS> Stop-Process -Name Idle
Stop-Process : Process 'Idle (0)' cannot be stopped due to the following error:
Access is denied
At line:1 char:13
+ Stop-Process <<<< -Name Idle
终结进程的能力取决于你的权限,有些进程无法被终结。
你也可以选择强制弹出确认提示,这个在你使用通配符匹配的时候会很有用。
PS> Stop-Process -Name t*,e* -Confirm
Confirm
Are you sure you want to perform this action?
Performing operation "Stop-Process" on Target "explorer (408)".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"):n
Confirm
Are you sure you want to perform this action?
Performing operation "Stop-Process" on Target "taskmgr (4072)".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"):n
复杂一点的进程操作,可以使用where来筛选执行对象,一个进程如果可以进行响应会返回true,可以利用这个性质,终结所有没有响应的应用
Get-Process | Where-Object -FilterScript {$_.Responding -eq $false} | Stop-Process
由于Stop-Process没有主机名选项ComputerName,所以远程停止其他电脑的进程,需要通过Invoke-Command来实现
Invoke-Command -ComputerName Server01 {Stop-Process Powershell}
003.终结所有其他powershell会话
PS> Get-Process -Name powershell | Where-Object -FilterScript {$_.Id -ne $PID} | Stop-Process -PassThru
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
334 9 23348 29136 143 1.03 388 powershell
304 9 23152 29040 143 1.03 632 powershell
302 9 20916 26804 143 1.03 1116 powershell
335 9 25656 31412 143 1.09 3452 powershell
303 9 23156 29044 143 1.05 3608 powershell
287 9 21044 26928 143 1.02 3672 powershell
02.管理服务
001.获取服务信息
Get-Service -Name se*
Status Name DisplayName
------ ---- -----------
Running seclogon Secondary Logon
Running SENS System Event Notification
Stopped ServiceLayer ServiceLayer
远程获取其他电脑的服务信息
Get-Service -ComputerName Server01
002.获取依赖进程和被依赖服务
Get-Service有两个在服务管理上比较使用的参数
DependentServices 参数获取依赖服务的其他服务
RequiredServices获取一个服务所依赖的服务。
下面的例子是获取LanmanWorkstation这个服务所依赖的服务。
PS> Get-Service -Name LanmanWorkstation -RequiredServices
Status Name DisplayName
------ ---- -----------
Running MRxSmb20 SMB 2.0 MiniRedirector
Running bowser Bowser
Running MRxSmb10 SMB 1.x MiniRedirector
Running NSI Network Store Interface Service
下面的命令获取依赖LanmanWorkstation的服务
PS> Get-Service -Name LanmanWorkstation -DependentServices
Status Name DisplayName
------ ---- -----------
Running SessionEnv Terminal Services Configuration
Running Netlogon Netlogon
Stopped Browser Computer Browser
Running BITS Background Intelligent Transfer Ser...
你甚至可以获取所有有依赖的服务。
Get-Service -Name * | Where-Object {$_.RequiredServices -or $_.DependentServices} |
Format-Table -Property Status, Name, RequiredServices, DependentServices -auto
003.停止,开始,挂起,和重启服务
Stop-Service -Name spooler
Start-Service -Name spooler
Suspend-Service -Name spooler
Restart-Service -Name spooler
03.管理Windows PowerShell Drives
Windows PowerShell Drives是一种数据存储位置,可以像访问磁盘驱动器一样进行访问。
里面为你创建了一些驱动器,比如c盘,d盘,还有注册表驱动器,证书驱动器等。
你也可以创建你自己的驱动器,但是这些驱动器只能在powershell中进行访问。资源管理器或者cmd中无法访问。
专有名词是PSDrive
PS> Get-PSDrive
Name Provider Root CurrentLocation
---- -------- ---- ---------------
A FileSystem A:\
Alias Alias
C FileSystem C:\ ...And Settings\me
cert Certificate \
D FileSystem D:\
Env Environment
Function Function
HKCU Registry HKEY_CURRENT_USER
HKLM Registry HKEY_LOCAL_MACHINE
Variable Variable
使用Get-Command命令查看语法
PS> Get-Command -Name Get-PSDrive -Syntax
Get-PSDrive [[-Name] <String[]>] [-Scope <String>] [-PSProvider <String[]>] [-V
erbose] [-Debug] [-ErrorAction <ActionPreference>] [-ErrorVariable <String>] [-
OutVariable <String>] [-OutBuffer <Int32>]
PSProvider 参数允许你选择特定的provider类型。
PS> Get-PSDrive -PSProvider FileSystem
Name Provider Root CurrentLocation
---- -------- ---- ---------------
A FileSystem A:\
C FileSystem C:\ ...nd Settings\PowerUser
D FileSystem D:\
你也可以使用常用的路径操作命令
PS> Set-Location HKLM:\SOFTWARE
PS> Push-Location .\Microsoft
PS> Get-Location
Path
----
HKLM:\SOFTWARE\Microsoft
001.添加新的Windows PowerShell Drives (New-PSDrive)
创建一个新的 Windows PowerShell drive,需要提供三个参数
- 驱动器的名字
- PSProvider,比如文件系统类型或者注册表类型
- 根路径的位置
比如创建一个名叫Office的新驱动器,映射一个文件夹,里面用于存放Office应用,
PS> New-PSDrive -Name Office -PSProvider FileSystem -Root "C:\Program Files\Microsoft Office\OFFICE11"
Name Provider Root CurrentLocation
---- -------- ---- ---------------
Office FileSystem C:\Program Files\Microsoft Offic...
注意:路径是大小写不敏感的。
Windows PowerShell drive可以简化一些任务,举个例子,一些注册表的键值可能有很长的路径。
创建powershell驱动器可以简化这些路径
比如
PS> New-PSDrive -Name cvkey -PSProvider Registry -Root HKLM\Software\Microsoft\Windows\CurrentVersion
Name Provider Root CurrentLocation
---- -------- ---- ---------------
cvkey Registry HKLM\Software\Microsoft\Windows\...
你可以在其他任何驱动器访问这个新建的驱动器
cd cvkey:
或者
PS> Set-Location cvkey: -PassThru
Path
----
cvkey:\
注意这个新建的驱动器只在当前会话中存在,关闭当前powershell窗口,这个新建的驱动器就会丢失。
如果想要永久保存这个驱动器,可以使用 Export-Console命令导出当前的powershell会话,
然后使用PowerShell.exe PSConsoleFile参数来导入这个会话文件,或者也可以写入powershell'的profile中。
002.删除Windows PowerShell Drivess(Remove-PSDrive)
Remove-PSDrive -Name Office
04.处理网络任务
001.获取电脑的IP地址
如果是获取本机的ip地址,执行以下命令
Get-CimInstance -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=$true |
Select-Object -ExpandProperty IPAddress
002.获取IP配置数据
获取每个网络适配器详细的ip配置信息,执行:
Get-CimInstance -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=$true
默认的输出格式比较难以查看,使用Select-Object或者 Format-List
来指定显示的属性
现代TCP/IP 网络上,你可能不会对 IPX或者WINS属性感兴趣,可以排除掉这些属性
Get-CimInstance -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=$true |
Select-Object -ExcludeProperty IPX*,WINS*
003.ping
可以使用Win32_PingStatus实现ping另一台电脑的功能
Get-CimInstance -Class Win32_PingStatus -Filter "Address='127.0.0.1'"
一个比较好的信息总结需要显示地址,响应时间和状态码属性,执行Format-Table命令来格式化输出
Get-CimInstance -Class Win32_PingStatus -Filter "Address='127.0.0.1'" |
Format-Table -Property Address,ResponseTime,StatusCode -Autosize
Address ResponseTime StatusCode
------- ------------ ----------
127.0.0.1 0 0
StatusCode 值为0表示一个成功的ping
你也可以使用数组去ping多台电脑
'127.0.0.1','localhost','research.microsoft.com' |
ForEach-Object -Process {
Get-CimInstance -Class Win32_PingStatus -Filter ("Address='$_'") |
Select-Object -Property Address,ResponseTime,StatusCode
}
可以用同样形式的命令ping一个网络的所有子网
1..254| ForEach-Object -Process {
Get-CimInstance -Class Win32_PingStatus -Filter ("Address='192.168.1.$_ '") } |
Select-Object -Property Address,ResponseTime,StatusCode
004.获取网络适配器信息
Get-CimInstance -Class Win32_NetworkAdapter -ComputerName .
005.给网络适配器更换DNS地址
需要用到Win32_NetworkAdapterConfiguration的SetDNSDomain 方法
Get-CimInstance -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=$true |
ForEach-Object -Process { $_.SetDNSDomain('fabrikam.com') }
IPEnabled属性是必要的,因为即使再一个只使用TCP/IP的网络上也会有一些不是TCP/IP的网络适配器。
也可以使用where进行过滤
Get-CimInstance -Class Win32_NetworkAdapterConfiguration |
Where-Object {$_.IPEnabled} |
ForEach-Object -Process {$_.SetDNSDomain('fabrikam.com')}
006.执行DHCP配置任务
寻找开启DHCP的网络适配器
Get-CimInstance -Class Win32_NetworkAdapterConfiguration -Filter "DHCPEnabled=$true"
再配置IP设置有问题的配置器
Get-CimInstance -Class Win32_NetworkAdapterConfiguration -Filter "IPEnabled=$true and DHCPEnabled=$true"
获取DHCP属性
因为DHCP相关的属性通常是DHCP开头的,所以
Get-CimInstance -Class Win32_NetworkAdapterConfiguration -Filter "DHCPEnabled=$true" |
Format-Table -Property DHCP*
开启每个适配器的DHCP
Get-CimInstance -Class Win32_NetworkAdapterConfiguration -Filter IPEnabled=$true |
ForEach-Object -Process {$_.EnableDHCP()}
可以用Filter 筛选掉那些已经启动DHCP的。
在特定适配器上Releasing 或者 Renewing DHCP协议
Get-CimInstance -Class Win32_NetworkAdapterConfiguration -Filter "IPEnabled=$true and DHCPEnabled=$true" |
Where-Object {$_.DHCPServer -contains '192.168.1.254'} |
ForEach-Object -Process {$_.ReleaseDHCPLease()}
在所有适配器上Releasing 或者 Renewing DHCP协议
通过列出所有WMI类,然后根据名字选择需要的类,就可以返回一个Win32_NetworkAdapterConfiguration 类而不是实例。
Get-CimInstance -List | Where-Object {$_.Name -eq 'Win32_NetworkAdapterConfiguration'}
你可以把整个命令当作一个class,然后调用ReleaseDHCPAdapterLease 方法,
(Get-CimInstance -List |
Where-Object {$_.Name -eq 'Win32_NetworkAdapterConfiguration'}).ReleaseDHCPLeaseAll()
同样的形式,可以调用RenewDHCPLeaseAll 方法
007.创建网络共享
(Get-CimInstance -List |
Where-Object {$_.Name -eq 'Win32_Share'}).Create(
'C:\temp','TempShare',0,25,'test share of the temp folder'
)
windows平台也可以使用 net share
命令
net share tempshare=c:\temp /users:25 /remark:"test share of the temp folder"
008.移除网络共享
(Get-CimInstance -Class Win32_Share -Filter "Name='TempShare'").Delete()
or(windows only)
net share tempshare /delete
009.连接windows可访问网络驱动器
之前讲了New-PSDrive创建一个powershell驱动器,如果需要通过网络访问驱动器可以使用WScript.Network COM object
执行以下命令把\FPS01\users 映射到b驱动器
(New-Object -ComObject WScript.Network).MapNetworkDrive('B:', '\\FPS01\users')
windows平台下可以使用net use
net use B: \\FPS01\users
05.软件安装
001.列出windows installer应用
Get-CimInstance -Class Win32_Product |
Where-Object Name -eq "Microsoft .NET Core Runtime - 2.1.5 (x64)"
这条命令执行还是比较慢的。
Get-CimInstance -Class Win32_Product |
Where-Object Name -eq "Microsoft .NET Core Runtime - 2.1.5 (x64)" |
Format-List -Property *
002.列出所有能卸载的应用
因为大多数标准应用都注册了卸载程序,可以从下面这个注册表里面找到
New-PSDrive -Name Uninstall -PSProvider Registry -Root HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
查看卸载程序的数目
(Get-ChildItem -Path Uninstall:).Count
列表用变量保存
$UninstallableApplications = Get-ChildItem -Path Uninstall:
显示名称
$UninstallableApplications | ForEach-Object -Process { $_.GetValue('DisplayName') }
查询特定
$UninstallableApplications | Where-Object -FilterScript {
$_.GetValue("DisplayName") -eq "Microsoft Silverlight"
}
003.安装应用
可以使用Win32_Product类安装应用,当然需要管理员权限。
Invoke-CimMethod -ClassName Win32_Product -MethodName Install -Arguments @{PackageLocation='\\AppSrv\dsp\NewPackage.msi'}
004.删除应用
Get-CimInstance -Class Win32_Product -Filter "Name='ILMerge'" | Invoke-CimMethod -MethodName Uninstall
可以通过删除字符串找到可以删除的程序
Get-ChildItem -Path Uninstall: | ForEach-Object -Process { $_.GetValue('UninstallString') }
Get-ChildItem -Path Uninstall: |
Where-Object -FilterScript { $_.GetValue('DisplayName') -like 'Win*'} |
ForEach-Object -Process { $_.GetValue('UninstallString') }
005.升级Windows Installer应用
Get-CimInstance -Class Win32_Product -Filter "Name='OldAppName'" |
Invoke-CimMethod -MethodName Upgrade -Arguments @{PackageLocation='\\AppSrv\dsp\OldAppUpgrade.msi'}
06.解码正在运行的powershell脚本
有时,我们会运行一些占用大量资源的powershell程序。当由多个powershell程序运行的时候,很难判断哪个程序出了问题。下面我们就展示如何从一个运行的powershell进程中解码代码块
001.创建一个运行时长比较长的进程
下面这个程序会每分钟输出一个数字,持续10分钟
powershell.exe -Command {
$i = 1
while ( $i -le 10 )
{
Write-Output -InputObject $i
Start-Sleep -Seconds 60
$i++
}
}
002.查看进程
执行的命令体会被存储在Win32_Process类的属性上,并且命令被编码了。依据这一信息我们可以用下面的步骤反混淆
以管理员模式打开powershell,执行下面的命令
获取到编码过的命令
$powerShellProcesses = Get-CimInstance -ClassName Win32_Process -Filter 'CommandLine LIKE "%EncodedCommand%"'
下面的步骤创建一个传统的powershell对象包括进程id和编码的命令
$commandDetails = $powerShellProcesses | Select-Object -Property ProcessId,
@{
name = 'EncodedCommand'
expression = {
if ( $_.CommandLine -match 'encodedCommand (.*) -inputFormat' )
{
return $matches[1]
}
}
}
然后编码的命令就能被解码了。
下面的代码片段,遍历命令对象,解码被编码的命令,将解码后的命令加回该对象,供进一步研究
$commandDetails | ForEach-Object -Process {
# Get the current process
$currentProcess = $_
# Convert the Base 64 string to a Byte Array
$commandBytes = [System.Convert]::FromBase64String($currentProcess.EncodedCommand)
# Convert the Byte Array to a string
$decodedCommand = [System.Text.Encoding]::Unicode.GetString($commandBytes)
# Add the decoded command back to the object
$commandDetails |
Where-Object -FilterScript { $_.ProcessId -eq $_.ProcessId } |
Add-Member -MemberType NoteProperty -Name DecodedCommand -Value $decodedCommand
}
$commandDetails[0]
查看会是下面的样子。
ProcessId : 8752
EncodedCommand : IAAKAAoACgAgAAoAIAAgACAAIAAkAGkAIAA9ACAAMQAgAAoACgAKACAACgAgACAAIAAgAHcAaABpAGwAZQAgACgAIAAkAGkAIAAtAG
wAZQAgADEAMAAgACkAIAAKAAoACgAgAAoAIAAgACAAIAB7ACAACgAKAAoAIAAKACAAIAAgACAAIAAgACAAIABXAHIAaQB0AGUALQBP
AHUAdABwAHUAdAAgAC0ASQBuAHAAdQB0AE8AYgBqAGUAYwB0ACAAJABpACAACgAKAAoAIAAKACAAIAAgACAAIAAgACAAIABTAHQAYQ
ByAHQALQBTAGwAZQBlAHAAIAAtAFMAZQBjAG8AbgBkAHMAIAA2ADAAIAAKAAoACgAgAAoAIAAgACAAIAAgACAAIAAgACQAaQArACsA
IAAKAAoACgAgAAoAIAAgACAAIAB9ACAACgAKAAoAIAAKAA==
DecodedCommand :
$i = 1
while ( $i -le 10 )
{
Write-Output -InputObject $i
Start-Sleep -Seconds 60
$i++
}