PowerShell 技能连载 - 使用 WMI 继承

适用于 PowerShell 所有版本

WMI 类是彼此继承的,我们可以利用这个特性。例如这行代码:

PS> Get-WmiObject -Class Win32_Printer

它将返回通过 WMI 获取到的所有打印机。打印机是从更多的通用类继承的,这段代码可以显示继承树:

PS> Get-WmiObject -Class Win32_Printer | Select-Object -ExpandProperty __derivation -First 1
CIM_Printer
CIM_LogicalDevice
CIM_LogicalElement
CIM_ManagedSystemElement

所以如果您不只是对打印机感兴趣,而是对更多的硬件感兴趣,那么选择更通用的父类,例如 CIM_LogicalDevice。这行代码可以获取所有的硬件清单:

PS> Get-WmiObject -Class CIM_LogicalDevice

Manufacturer        Name                Status                       StatusInfo
------------        ----                ------                       ----------
Realtek             Realtek High Def... OK                                    3
                    Kona                OK
Intel Corporation   Intel(R) 8 Serie... OK
Intel Corporation   Intel(R) Wireles...
Microsoft           Microsoft Kernel...
                    ASIX AX88772B US...
Microsoft           Virtueller Micro...
Microsoft           Bluetooth-Gerät ...
Microsoft           Microsoft-ISATAP...
                    Microsoft-ISATAP...
Microsoft           Teredo Tunneling...
Microsoft           Von Microsoft ge...
                    Microsoft-ISATAP...
                    Microsoft-ISATAP...
                    Microsoft-ISATAP...
                    Microsoft-ISATAP...
                    ASIX AX88772B US...
                    Microsoft-ISATAP...
                    Microsoft-ISATAP...
                    Virtueller Micro...
                    Microsoft-ISATAP...
                    Microsoft-ISATAP...
                    Microsoft-ISATAP...
-Virtual Battery 0- CRB Battery 0
(...)

这段代码将返回有关的类,这样的您就可以清晰地看到 WMI 如何调用您的硬件类型:

PS> Get-WmiObject -Class CIM_LogicalDevice |
  Group-Object -Property __Class -NoElement

Count Name
----- ----
    1 Win32_SoundDevice
    1 Win32_Battery
    1 Win32_IDEController
   20 Win32_NetworkAdapter
    1 Win32_PortableBattery
   10 Win32_Printer
    1 Win32_Processor
    2 Win32_DiskDrive
    7 Win32_DiskPartition
    1 Win32_Fan
    2 Win32_Keyboard
    5 Win32_LogicalDisk
    2 Win32_MappedLogicalDisk
    1 Win32_MemoryArray
    2 Win32_MemoryDevice
    2 Win32_PointingDevice
    1 Win32_SCSIController
    2 Win32_USBController
    6 Win32_USBHub
    5 Win32_Volume
    4 Win32_CacheMemory
    1 Win32_DesktopMonitor
    1 Win32_VideoController
    1 Win32_VoltageProbe
    1 Win32_MotherboardDevice
    8 Win32_Bus
  134 Win32_PnPEntity

It basically takes all the instances derived from CIM_LogicalDevice and groups them by “__Class” which is their real class name.
它基本上获取从 CIM_LogicalDevice 继承的所有实例并按照“__Class”分组。这是它们的真实类名。

PowerShell 技能连载 - 获取系统启动时间

适用于 PowerShell 所有版本

这个简单的函数可以返回当前系统的启动时间:

function Get-Uptime
{
  $millisec = [Environment]::TickCount
  [Timespan]::FromMilliseconds($millisec)
}

PowerShell 技能连载 - 查找进程所有者

适用于 PowerShell 所有版本

要查看某个进程的所有者以及有多少个实例在运行,请试试以下这段代码:

$ProcessName = 'explorer.exe'

(Get-WmiObject -Query "select * from Win32_Process where name='$ProcessName'").GetOwner().User

请注意:有许多办法能够查看当前登录的用户,并且根据您使用环境的不同,这里展示的方法可能有一定的局限性。它假设当前用户使用图形界面登录。由于在 server core 的机器上,只能运行非图形界面的进程,所以该脚本在该情况下不能检测连接到主机的用户名。

这个例子返回这台机器上所有“explorer.exe”进程的所有者。如果您有管理员权限并且远程进行此操作,那么该用户列表将类似已交互式登录的用户,因为每个桌面用户都创建了一个 explorer 进程。

当加入一个 Sort-Object 命令之后,您就可以轻松地排除重复项:

$ProcessName = 'explorer.exe'

(Get-WmiObject –Query "select * from Win32_Process where name='$ProcessName'").GetOwner().User |
  Sort-Object -Unique

如果改变进程名,您会发现其它有趣的东西。这段代码将列出当前通过 PowerShell 远程操作访问您机器的所有用户:

$ProcessName = 'wsmprovhost.exe'

try
{

  (Get-WmiObject -Query "select * from Win32_Process where name='$ProcessName'").GetOwner().User |
  Sort-Object -Unique
}
catch
{
  Write-Warning "No user found."
}

PowerShell 技能连载 - 解析 DISM 日志文件

适用于 PowerShell 2.0 及更高版本

在您的 Windows 文件夹中,您会见到各种系统日志文件。其中一种是 DISM 日志文件,它包含了 Windows 的配置信息(特性状态等)。

以下是一个简单的实践,演示如何解析这类日志文件并得到可用 PowerShell cmdlet 操作的富对象:

$path = "$env:windir\logs\dism\dism.log"

Get-Content -Path $path |
ForEach-Object {
  $_ -replace '\s{2,}', ','
} |
ConvertFrom-Csv -Header (1..20) |
ForEach-Object {
  $array = @()
  $array += $_.1 -split ' '
  $array += $_.2
  $array += $_.3
  $array += $_.4
  $array += $_.5
  $array -join ','
} |
ConvertFrom-Csv -Header (1..20) |
Out-GridView

PowerShell 技能连载 - 设置 Active Directory 属性

需要 ActiveDirectory 模块

PowerShell 用哈希表来设置一个用户账户的 AD 属性这是一种多功能的指定任意键值对的方法。

这个简单的例子将设置用户“_testuser_”的“_l_”和“_mail_”属性。您可以向哈希表加入任意多的键值对,假设在您的 AD schema 中不存在该属性名,并且指定的数据类型是合法的:

$infos = @{}
$infos.l = 'Bahamas'
$infos.mail = 'sunny@offshore.com'

Set-ADUser -Identity testuser -Replace $infos

PowerShell 技能连载 - 根据 Excel 表批量创建 AD 用户

需要 ActiveDirectory Module

为了创建大量新的 Active Directory 用户,您可以从 CSV 文件中导入用户信息,这个 CSV 可以由 Excel 表导出。

下一步,这段代码将会把 CSV 数据转为真实的 Active Directory 用户账户。

Import-Csv -Path F:\userlist.csv -UseCulture -Encoding Default |
ForEach-Object {

  $_.AccountPassword = $_.AccountPassword |
                           ConvertTo-SecureString -Force -AsPlainText
  $_

} |
New-ADUser -WhatIf

CSV 文件所需的只是 New-ADUser 所需要的参数作为列名。一个详尽的列表可能包含以下列名:NameSamAccountNameDescriptionCompanyCityPathAccountPassword

请注意 CSV 文件天生只能包含字符串数据类型。由于 AccountPassword 属性需要一个 SecureString 数据类型的值,所以 PowerShell 代码将从 CSV 文件中读取字符串转换为 SecureString 之后再传递给 New-ADUser

这个技术可以用于创建用户前预处理任何原始数据。

PowerShell 技能连载 - PowerShell 技能连载 - 移除 AD 组成员

需要 ActiveDirectory Module

要从 Active Directory 组中移除一个或多个用户,尝试以下方法:

1
2
3
4
5
6
$user = @()
$user += Get-ADUser -Filter { Name -like 'H*'}
$user += Get-ADUser -Filter { Name -like '*ll*'}
$user.Name

Remove-ADGroupMember -Identity 'SomeGroup' -Members $user

这段代码将查找名字符合指定模式的所有用户,然后将用户列表传递给 Remove-ADGroupMember 来将用户从该组中移除掉。

请注意空数组的使用。一个空数组可以通过“+=”运算符一次或多次加入元素,并且该操作符可以接受单个用户也可以接受一个数组。所以您可以向列表添加一个或多个用户——例如过滤查询的结果。

PowerShell 技能连载 - PowerShell 技能连载 - 配置 PowerShell 的步骤(第 3 部分)

适用于 PowerShell 所有版本

如果您在家中或其它不重要的场合使用 PowerShell,那么可以通过以下步骤使 PowerShell 发挥最大功能。

要在您自己的的机器上启用 PowerShell 远程操作,您需要在您的机器上启用 PowerShell 远程操作功能。实现的方式是用管理员权限启动 PowerShell,然后运行该命令:

1
PS> Enable-PSRemoting -SkipNetworkProfileCheck -Force

请注意 -SkipNetworkProfileCheck 是 PowerShell 3.0 引入的概念。如果您仍在 使用 PowerShell 2.0,请忽略这个参数。如果 PowerShell 提示公用网络连接可用,您需要手动临时禁用公用网络连接。

该命令在您的机器上启用 PowerShell 远程操作。其他人现在可以连接到您的计算机,如果他是您计算机上的 Administrators 组成员。

然而,您只能用 Kerberos 身份验证方式来连接到别的计算机。所以此时,远程操作只适用于域环境。如果您在一个简单的点对点网络环境中或是想跨域使用远程操作功能,那么需要启用 NTLM 验证。请注意:只需要在客户端设置。不是在您想连接的目标机器上设,而是在您发起远程操作的机器上设:

1
PS> Set-Item -Path WSMan:\localhost\Client\TrustedHosts -Value * -Force

使用“*”允许您通过 NTLM 验证方式连接到任何目标机器。由于 NTLM 是一种非双向认证方式,所以当您使用该方式连接到一台不受信任或可能已被入侵的机器时,会增加安全风险。所以最好不要用“*”,而是指定 IP 地址或 IP 地址段,例如“10.10.*”。

当设置好 PowerShell 远程操作之后,您可以开始使用。

这行代码将会在 ABC 机器上运行任意的 PowerShell 代码(需要您事先在 ABC 机器上启用远程操作功能,并且拥有 ABC 机器上的管理员权限):

1
PS> Invoke-Command -ScriptBlock { "Hello" > c:\IwasHERE.txt } -ComputerName ABC

这段代码将实现同样的效果,但这里您需要显式地制定凭据。当您指定了一个账户,请确定指定了域名和用户名。如果它不是一个域账户,请指定机器名和用户名:

1
Invoke-Command -ScriptBlock { "Hello" > c:\IwasHERE.txt } -ComputerName ABC -Credential ABC\localAdminAccount

请注意:当您想用非 Kerberos 验证的时候,加入域的计算机需要使用 -Credential 参数。

PowerShell 技能连载 - 配置 PowerShell 的步骤(第 2 部分)

适用于 PowerShell 2.0 及以上版本

如果您在家中或其它不重要的场合使用 PowerShell,那么可以通过以下步骤使 PowerShell 发挥最大功能。

要允许系统管理员远程连接到您的机器并运行 Get-ProcessGet-Service 等 cmdlets,您也许需要启用远程管理的防火墙例外规则。请以管理员身份打开 PowerShell 并运行这段代码:

1
2
3
4
5
6
7
8
9
10
PS> netsh firewall set service remoteadmin enable

IMPORTANT: Command executed successfully.
However, "netsh firewall" is deprecated;
use "netsh advfirewall firewall" instead.
For more information on using "netsh advfirewall firewall" commands
instead of "netsh firewall", see KB article 947709
at http://go.microsoft.com/fwlink/?linkid=121488 .

Ok.

该命令返回的信息告诉我们该命令已过时,有一个更新的命令替代了它,但它任然可用并启用了防火墙例外。新的命令更难使用,因为它的参数是本地化的,并且您需要知道防火墙例外的确切名称。

要真正地用上 cmdlet 的远程功能,您还需要启用 RemoteRegistry 服务并将它设为自动启动:

1
2
3
PS> Start-Service RemoteRegistry

PS> Set-Service -Name Remoteregistry -StartupType Automatic

您现在可以使用 Get-ProcessGet-Service 或其它暴露了 -ComputerName 参数的 cmdlet 来远程连接到您的计算机,假设运行这些 cmdlet 的用户拥有您系统上的管理员权限。

在简单的点对点家庭环境中,为每台计算机的 Administrator 账号设置相同的名字就足够了。

PowerShell 技能连载 - 配置 PowerShell 的步骤(第 1 部分)

适用于 PowerShell 2.0 及以上版本

如果您在家中或其它不重要的场合使用 PowerShell,那么可以通过以下步骤使 PowerShell 发挥最大功能。

您可以通过以下代码查看正在使用的 PowerShell 版本:

1
2
3
PS> $PSVersionTable.PSVersion.Major

4

如果版本号小于 4,请审查一下为什么使用过期的版本,是不是可以升级了。

要启用脚本执行功能,请运行以下代码:

1
PS> Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Bypass -Force

您现在可以自由地执行任意位置的脚本了。如果您是初学者并且希望得到更多的安全保障,请将“Bypass”改为“RemoteSigned”。这将防止您运行下载自 Internet 或电子邮件附件的脚本。它也将防止您运行您拥有的域之外的脚本。