PowerShell 技能连载 - 通过 Windows 10 开始菜单快速打开 PowerShell

在 Windows 10 中,PowerShell 可以通过 WIN + X 键(或右键单击开始菜单图标)启动。如果您的 Windows 10 打开的是过时的 cmd.exe,那么该快速做出改变了。

单击开始菜单图标(或按 WIN 键)。在开始菜单中,单击“齿轮”图标打开 Windows 设置。您现在可以看到一个有许多图标的,名为“Windows 设置”的窗口,在顶部有一个叫做“查找设置”的文本框。在文本框中输入 “PowerShell” 即可打开“使用 Windows + X 菜单时,将命令提示符替换为 Windows PowerShell”。

PowerShell 技能连载 - 测试 AD 用户是否存在

如果您需要查看一个指定的域用户是否存在,并且假设您已经安装了 ActiveDirectory PowerShell 模块,它是 RSAT(远程服务器管理工具)的一部分,那么有一个更巧的方法:

1
2
3
4
5
6
7
8
9
10
11
12
function Test-UserExists
{
param
(
[Parameter(Mandatory)]
[string]
$SAMAccountName
)

@(Get-ADUser -LDAPFilter "(samaccountname=$SAMAccountName)").Count -ne 0

}

您也可以调整 LDAP 查询来基于其它属性检查用户。

PowerShell 技能连载 - WMI 快速入门(第 4 部分)

通常,WMI 对象有许多包含重要信息的属性。这行代码将获取所有运行中的记事本实例的所有信息(请先运行记事本):

1
2
3
4
5
6
7
Get-WmiObject -Class Win32_Process -Filter 'Name LIKE "%notepad%"'
···

类似的,这行代码用 `Get-CimInstance` 获取相同的信息:

```powershell
Get-CimInstance -Class Win32_Process -Filter 'Name LIKE "%notepad%"'

有些时候,WMI 对象也包含方法。获取方法名最简单的方法是用 Get-WmiObject,然后将结果通过管道传送给 Get-Member 命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
PS> Get-WmiObject -Class Win32_Process -Filter 'Name LIKE "%notepad%"' | Get-Member -MemberType *method


TypeName: System.Management.ManagementObject#root\cimv2\Win32_Process

Name MemberType Definition
---- ---------- ----------
AttachDebugger Method System.Management.ManagementBaseObject AttachDebugger()
GetAvailableVirtualSize Method System.Management.ManagementBaseObject GetAvailableVirtualSize()
GetOwner Method System.Management.ManagementBaseObject GetOwner()
GetOwnerSid Method System.Management.ManagementBaseObject GetOwnerSid()
SetPriority Method System.Management.ManagementBaseObject SetPriority(System.Int32 Priority)
Terminate Method System.Management.ManagementBaseObject Terminate(System.UInt32 Reason)
ConvertFromDateTime ScriptMethod System.Object ConvertFromDateTime();
ConvertToDateTime ScriptMethod System.Object ConvertToDateTime();

要调用一个方法,例如获取一个进程的所有者时,Get-WmiObjectGet-CimInstance 之间有一个基本的区别:

当您通过 Get-WmiObject 获取对象时,对象的方法是返回对象的一部分:

1
2
3
4
$notepads = Get-WmiObject -Class Win32_Process -Filter 'Name LIKE "%notepad%"'
$notepads | ForEach-Object {
$notepads.GetOwner()
}

通过 Get-CimInstance 返回的对象不包含 WMI 方法。要调用 WMI 方法,您需要调用 Invoke-CimMethod

1
2
3
4
5
$notepads = Get-CimInstance -Class Win32_Process -Filter 'Name LIKE "%notepad%"'
$notepads |
ForEach-Object {
Invoke-CimMethod -InputObject $_ -MethodName "GetOwner"
}

在以上的代码中,假设您移除 GetOwner,而是按下 CTRL + SPACE 键调出智能感知(或在简单 PowerShell 控制台中按 TAB 键),您可以获得所有可用的方法名称。如果一个方法需要参数,请使用 -Arguments 参数。

PowerShell 技能连载 - WMI 快速入门(第 3 部分)

在前一个技能中我们解释了为什么 Get-CimInstance 比旧的 Get-WmiObject cmdlet 有优势。

这是另一个例子,演示了为什么 Get-CimInstance 可能会比 Get-WmiObject 快得多。

当您需要从远程主机查询多个 WMI 类,例如您需要创建一个库存报告,每次运行 cmdlet 时 Get-WmiObject 需要连接和断开连接。然而 Get-CimInstance 可以复用已有的 session。

以下是一个演示如何在两个查询中复用同一个 session 的例子:

1
2
3
4
5
6
7
8
9
10
# create the session
$options = New-CimSessionOption -Protocol Wsman
$session = New-CimSession -ComputerName sr0710 -SessionOption $options

# reuse the session for as many queries as you like
$sh = Get-CimInstance -ClassName Win32_Share -CimSession $session -Filter 'Name="Admin$"'
$se = Get-CimInstance -ClassName Win32_Service -CimSession $session

# remove the session at the end
Remove-CimSession -CimSession $session

当您需要连接到不支持 WSMan 的旧的计算机,只需要将以上代码的协议改为 DCOM 即可:将 Wsman 替换为 Dcom

PowerShell 技能连载 - WMI 快速入门(第 2 部分)

有两个 cmdlet 可以获取 WMI 数据:旧的 Get-WmiObject cmdlet 和新的 Get-CimInstance cmdlet。当在本地使用时,两者的行为十分相像。然而当远程使用的时候,两者的区别十分明显。

以下是两个示例调用,分别从远程系统中获取共享的文件(请确保调整了计算机名):

1
2
Get-WmiObject -Class Win32_Share -ComputerName sr0710
Get-CimInstance -ClassName Win32_Share -ComputerName sr0710

(两个调用都需要目标计算机的本地的管理员权限,所以您可能需要添加 Credential 参数并且提交一个合法的账户名,如果您当前的用户不满足这些要求的话)

Get-WmiObject 总是使用 DCOM 做为传输协议,而 Get-CimInstance 使用 WSMAN(一种 WebService 类的通信协议)。多数主流的 Windows 操作系统支持 WSMan,但如果您需要和旧的服务器通信,它们可能只支持 DCOM,这样 Get-CimInstance 可能会失败。

Get-CimInstance 可以使用 session 参数,这提供了巨大的灵活性,而且运行您选择传输协议。要使用 DCOM(类似 Get-WmiObject),请使用以下代码:

1
2
3
4
$options = New-CimSessionOption -Protocol Dcom
$session = New-CimSession -ComputerName sr0710 -SessionOption $options
$sh = Get-CimInstance -ClassName Win32_Share -CimSession $session
Remove-CimSession -CimSession $session

PowerShell 技能连载 - WMI 快速入门(第 1 部分)

WMI 是管理员的一个有用的信息源。您所需要的知识 WMI 类的名字,它代表了您感兴趣的东西。查找合法的 WMI 类名的最简单方法是搜索。

这行代码返回所有名字中包含 “Share” 的类:

1
Get-WmiObject -Class *share* -List

下一步,用 Get-WmiObject 获取一个类的所有实例:

1
Get-WmiObject -Class win32_share

如果您想查看所有属性,请别忘了将结果通过管道输出到 Select-Object 指令:

1
Get-WmiObject -Class win32_share | Select-Object -Property *

一个更好的方法是使用 Get-CimInstance 而不是 Get-WmiObject 因为它能自动转换数据类型,例如 DateTime

这个调用和 Get-WmiObject 的效果基本相同:

1
Get-CimInstance -ClassName Win32_Share

现在,您可以看到其中的区别:

1
2
3
4
5
Get-CimInstance -ClassName Win32_OperatingSystem |
Select-Object -Property Name, LastBootupTime, OSType

Get-WmiObject -Class Win32_OperatingSystem |
Select-Object -Property Name, LastBootupTime, OSType

PowerShell 技能连载 - 列出属性和值(第 3 部分)

当您希望检查单个对象和它的属性时,将对象用管道输出到 Out-GridView 指令不是太方便:网格视图窗口显示一个(非常长的)单行属性。试试这行代码,自己体验一下:

1
PS> Get-Process -Id $pid | Select-Object -Property * | Out-GridView

我们之前用过以下函数来对所有没有值的属性排序。但是这个函数还能做更多的事。他支持 -AsHashtable 参数,能将一个对象转换为哈希表,可以有效地帮助您显示单个对象的详细内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# Only list output fields with content

function Remove-EmptyProperty {
param (
[Parameter(Mandatory,ValueFromPipeline)]
$InputObject,

[Switch]
$AsHashTable
)


begin
{
$props = @()

}

process {
if ($props.COunt -eq 0)
{
$props = $InputObject |
Get-Member -MemberType *Property |
Select-Object -ExpandProperty Name |
Sort-Object
}

$notEmpty = $props | Where-Object {
!($InputObject.$_ -eq $null -or
$InputObject.$_ -eq '' -or
$InputObject.$_.Count -eq 0) |
Sort-Object

}

if ($AsHashTable)
{
$notEmpty |
ForEach-Object {
$h = [Ordered]@{}} {
$h.$_ = $InputObject.$_
} {
$h
}
}
else
{
$InputObject |
Select-Object -Property $notEmpty
}
}
}

当指定了 -AsHashtable 以后,Out-GridView 纵向显示对象内容,而不是水平显示。而且由于它叶移除了所有空白属性并按字母顺序对属性排序,它变得更容易查看和检视对象:

1
PS> Get-Process -Id $pid | Select-Object -Property * | Remove-EmptyProperty -AsHashTable | Out-GridView

例如把它用在 AD 用户对象上:

1
PS> Get-ADUser $env:username -Properties * | Remove-EmptyProperty -AsHashTable | Out-GridView

PowerShell 技能连载 - 列出属性和值(第 2 部分)

在前一个技能中我们介绍了一个名为 Remove-EmptyProperty 的新函数,它能够移除所有没有值的属性。现在让我们将它扩展一点,使它的对象属性按字母顺序排序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# Only list output fields with content

function Remove-EmptyProperty {
param (
[Parameter(Mandatory,ValueFromPipeline)]
$InputObject,

[Switch]
$AsHashTable
)


begin
{
$props = @()

}

process {
if ($props.COunt -eq 0)
{
$props = $InputObject |
Get-Member -MemberType *Property |
Select-Object -ExpandProperty Name |
Sort-Object
}

$notEmpty = $props | Where-Object {
!($InputObject.$_ -eq $null -or
$InputObject.$_ -eq '' -or
$InputObject.$_.Count -eq 0) |
Sort-Object

}

if ($AsHashTable)
{
$notEmpty |
ForEach-Object {
$h = [Ordered]@{}} {
$h.$_ = $InputObject.$_
} {
$h
}
}
else
{
$InputObject |
Select-Object -Property $notEmpty
}
}
}

当运行它以后,所有属性将会按字母顺序排序,这样要查找一个特定的属性变得十分容易:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
PS> Get-Process -Id $pid | Remove-EmptyProperty


__NounName : Process
BasePriority : 8
Company : Microsoft Corporation
CPU : 162,953125
Description : Windows PowerShell ISE
FileVersion : 10.0.16299.15 (WinBuild.160101.0800)
Handle : 5708
HandleCount : 1345
Handles : 1345
Id : 14340
MachineName : .
MainModule : System.Diagnostics.ProcessModule (PowerShell_ISE.exe)
MainWindowHandle : 10033714
MainWindowTitle : C:\Users\tobwe
MaxWorkingSet : 1413120
MinWorkingSet : 204800
Modules : {System.Diagnostics.ProcessModule (PowerShell_ISE.exe), System.Diagnostics.ProcessModule
(ntdll.dll), System.Diagnostics.ProcessModule (MSCOREE.DLL), System.Diagnostics.ProcessModule
(KERNEL32.dll)...}
Name : powershell_ise
NonpagedSystemMemorySize : 86544
NonpagedSystemMemorySize64 : 86544
NPM : 86544
PagedMemorySize : 335093760
PagedMemorySize64 : 335093760
PagedSystemMemorySize : 1277432
PagedSystemMemorySize64 : 1277432
Path : C:\WINDOWS\system32\WindowsPowerShell\v1.0\PowerShell_ISE.exe
PeakPagedMemorySize : 389857280
PeakPagedMemorySize64 : 389857280
PeakVirtualMemorySize : 1601478656
PeakVirtualMemorySize64 : 1601478656
PeakWorkingSet : 423972864
PeakWorkingSet64 : 423972864
PM : 335093760
PriorityBoostEnabled : True
PriorityClass : Normal
PrivateMemorySize : 335093760
PrivateMemorySize64 : 335093760
PrivilegedProcessorTime : 00:00:34.2187500
ProcessName : powershell_ise
ProcessorAffinity : 15
Product : Microsoft® Windows® Operating System
ProductVersion : 10.0.16299.15
Responding : True
SafeHandle : Microsoft.Win32.SafeHandles.SafeProcessHandle
SessionId : 1
SI : 1
StartInfo : System.Diagnostics.ProcessStartInfo
StartTime : 04.04.2018 08:55:57
Threads : {16712, 12844, 15764, 1992...}
TotalProcessorTime : 00:02:42.9531250
UserProcessorTime : 00:02:08.7343750
VirtualMemorySize : 1485922304
VirtualMemorySize64 : 1485922304
VM : 1485922304
WorkingSet : 354381824
WorkingSet64 : 354381824
WS : 354381824

PowerShell 技能连载 - 列出属性和值(第 1 部分)

对象中有丰富的信息,但是对象也可能有空的属性。尤其是从 Active Directory 中获取的对象。

以下是一个名为 Remove-EmptyProperty 的有用的函数,能够接受任意的对象并移除所有空属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# Only list output fields with content

function Remove-EmptyProperty {
param (
[Parameter(Mandatory,ValueFromPipeline)]
$InputObject,

[Switch]
$AsHashTable
)


begin
{
$props = @()

}

process {
if ($props.COunt -eq 0)
{
$props = $InputObject |
Get-Member -MemberType *Property |
Select-Object -ExpandProperty Name
}

$notEmpty = $props | Where-Object {
!($InputObject.$_ -eq $null -or
$InputObject.$_ -eq '' -or
$InputObject.$_.Count -eq 0) |
Sort-Object

}

if ($AsHashTable)
{
$notEmpty |
ForEach-Object {
$h = [Ordered]@{}} {
$h.$_ = $InputObject.$_
} {
$h
}
}
else
{
$InputObject |
Select-Object -Property $notEmpty
}
}
}

以下是一个例子,演示如何使用该函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
PS> Get-Process -Id $pid

Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
1432 87 324452 346012 145,13 14340 1 powershell_ise



PS> Get-Process -Id $pid | Remove-EmptyProperty


Handles : 1256
Name : powershell_ise
NPM : 85320
PM : 332496896
SI : 1
VM : 1491988480
WS : 363655168
__NounName : Process
BasePriority : 8
Handle : 5776
HandleCount : 1256
Id : 14340
MachineName : .
MainModule : System.Diagnostics.ProcessModule (PowerShell_ISE.exe)
MainWindowHandle : 10033714
MainWindowTitle : C:\Users\tobwe
MaxWorkingSet : 1413120
MinWorkingSet : 204800
Modules : {System.Diagnostics.ProcessModule (PowerShell_ISE.exe), System.Diagnostics.ProcessModule
(ntdll.dll), System.Diagnostics.ProcessModule (MSCOREE.DLL), System.Diagnostics.ProcessModule
(KERNEL32.dll)...}
NonpagedSystemMemorySize : 85320
NonpagedSystemMemorySize64 : 85320
PagedMemorySize : 332496896
PagedMemorySize64 : 332496896
PagedSystemMemorySize : 1272400
PagedSystemMemorySize64 : 1272400
PeakPagedMemorySize : 389857280
PeakPagedMemorySize64 : 389857280
PeakVirtualMemorySize : 1601478656
PeakVirtualMemorySize64 : 1601478656
PeakWorkingSet : 423972864
PeakWorkingSet64 : 423972864
PriorityBoostEnabled : True
PriorityClass : Normal
PrivateMemorySize : 332496896
PrivateMemorySize64 : 332496896
PrivilegedProcessorTime : 00:00:30.6250000
ProcessName : powershell_ise
ProcessorAffinity : 15
Responding : True
SafeHandle : Microsoft.Win32.SafeHandles.SafeProcessHandle
SessionId : 1
StartInfo : System.Diagnostics.ProcessStartInfo
StartTime : 04.04.2018 08:55:57
Threads : {16712, 12844, 15764, 1992...}
TotalProcessorTime : 00:02:26.2656250
UserProcessorTime : 00:01:55.6406250
VirtualMemorySize : 1491988480
VirtualMemorySize64 : 1491988480
WorkingSet : 363655168
WorkingSet64 : 363655168
Company : Microsoft Corporation
CPU : 146,265625
Description : Windows PowerShell ISE
FileVersion : 10.0.16299.15 (WinBuild.160101.0800)
Path : C:\WINDOWS\system32\WindowsPowerShell\v1.0\PowerShell_ISE.exe
Product : Microsoft® Windows® Operating System
ProductVersion : 10.0.16299.15




PS>

Remove-EmptyProperty 基本上是创建一个只包含实际值的属性。由于它总是创建一个新对象,所以它有副作用:您总是会看到缺省情况下隐藏的属性。

PowerShell 技能连载 - 允许远程处理

cmdlet 有许多方法可以从另一台计算机远程获取信息。以下只是其中的一些方法:

1
2
3
4
5
6
7
8
9
10
# try and connect to this computer
# (adjust it to a valid name in your network)
$destinationServer = "SERVER12"

# PowerShell remoting
$result1 = Invoke-Command { Get-Service } -ComputerName $destinationServer

# built-in
$result2 = Get-Service -ComputerName $destinationServer
$result3 = Get-Process -ComputerName $destinationServer

非常可能的情况是,缺省情况下远程访问不可用。受限,对于许多远程技术您需要目标端的管理员权限。但是即便您拥有该权限,客户操作系统的远程访问缺省情况下也是禁用的。

如果您希望在测试机上打开最常用的远程技术,请在用管理员权限打开的 PowerShell 中运行以下代码:

1
2
netsh firewall set service remoteadmin enable
Enable-PSRemoting -SkipNetworkProfileCheck -Force

虽然第一条命令是已过时的,但仍然有效。它将管理员远程功能添加到防火墙例外中,允许基于 DCOM 的远程处理。第二行启用 PowerShell 远程处理。