PowerShell 技能连载 - 限制 String 的最大长度
适用于 PowerShell 所有版本
要限制输出的文本不会过长,您可以使用类似这样的的逻辑来缩短超过指定长度的文本:
if ($text.Length -gt $MaxLength)
{
$text.Substring(0,$MaxLength) + '...'
}
else
{
$text
}
适用于 PowerShell 所有版本
要限制输出的文本不会过长,您可以使用类似这样的的逻辑来缩短超过指定长度的文本:
if ($text.Length -gt $MaxLength)
{
$text.Substring(0,$MaxLength) + '...'
}
else
{
$text
}
需要 ActiveDirectory 模块
我们之前已经演示了如何用 Get/Set-Acl
来读写文件和文件夹的权限。
实际上这两个 cmdlet 可以处理所有合法的 PowerShell 路径。说以您可以同样地在 Windows 注册表中使用相同的方法来读取、克隆和写入属性。
这个例子从一个注册表键中读取已有的安全信息,并应用到另一个键上:
# both Registry keys must exist
$KeyToCopySecurityFrom = 'HKLM:\Software\Key1'
$KeyToCopySecurityTo = 'HKLM:\Software\Key1'
$securityDescriptor = Get-Acl -Path $KeyToCopySecurityFrom
Set-Acl -Path $KeyToCopySecurityTo -AclObject $securityDescriptor
类似地,如果您从微软安装了 RSAT 工具并启用了 ActiveDirectory PowerShell 模块,您就可以使用它的 PowerShell 驱动器 AD: 来对 AD 对象做类似的操作,例如,从一个 OU 克隆委派权限到另一个 OU 上。
您现在可以根据需要读取、修改或重新应用如委派控制、防止意外删除等 Active Directory 特性。
Import-Module ActiveDirectory
# both OUs must exist
$OUtoCopyFrom = 'AD:\OU=Employees,DC=TRAINING,DC=POWERSHELL'
$OUtoCopyTo = 'AD:\OU=TestEmployees,DC=TRAINING,DC=POWERSHELL'
$securityDescriptor = Get-Acl -Path $OUtoCopyFrom
Set-Acl -Path $OUtoCopyTo -AclObject $securityDescriptor
您现在可以对任何 AD 对象通过这种方式读取和写入安全信息,包括 DNS 信息。您所需要的只是知道您想读写的对象的 LDAP 路径。
适用于 PowerShell 所有版本
以下是检测控制台程序发出的错误的另一种方法:
$ErrorActionPreference = 'Continue'
$result = net.exe user UserDoesNotExist 2>&1
# $? is $false when something went wrong
if ($? -eq $false) {
# read last error:
$errMsg = $result.Exception.Message -join ','
Write-Host "Something went wrong: $errMsg"
} else {
Write-Host 'All is fine.'
}
请注意 $ErrorActionPreference
的用法:当它设置为‘Stop
’时,错误将被转换为一个 .NET 异常。$ErrorActionPreference
的缺省设置是‘Continue
’。通过这个设置,脚本可以通过 $err
获得错误信息。
如果最后一次调用失败了,内置的 $?
变量将会返回 $false
。在这种情况下,代码将会返回一条错误信息(或者做其它事情,例如写日志文件)。
适用于 PowerShell 所有版本
您可以通过 Get-Acl
命令将文件和文件夹的安全信息导出成 SDDL 格式(安全描述定义语言)的纯文本文件:
$FolderToRead = 'C:\folder1'
$securityDescriptor = Get-Acl -Path $FolderToRead
$securityDescriptor.GetSecurityDescriptorSddlForm('All')
您可以将 SDDL 通过管道输出到剪贴板,然后将它粘贴到另一个脚本中:
$FolderToRead = 'C:\folder1'
$securityDescriptor = Get-Acl -Path $FolderToRead
$securityDescriptor.GetSecurityDescriptorSddlForm('All') | clip.exe
类似这样将 SDDL 加入脚本中,例如(请注意 SDDL 总是只有一行,所以请不要添加换行符):
$sddl = 'O:S-1-5-21-2649034417-1209187175-3910605729-1000G:S-1-5-21-2649034417-1209187175-3910605729-513D:(A;ID;FA;;;BA)(A;OICIIOID;GA;;;BA)(A;ID;FA;;;SY)(A;OICIIOID;GA;;;SY)(A;OICIID;0x1200a9;;;BU)(A;ID;0x1301bf;;;AU)(A;OICIIOID;SDGXGWGR;;;AU)'
$FolderToConfigure = 'C:\folder2'
$securityDescriptor = Get-Acl -Path $FolderToConfigure
$securityDescriptor.SetSecurityDescriptorSddlForm($sddl)
Set-Acl -Path $FolderToConfigure -AclObject $securityDescriptor
将 SDDL 插入脚本之后,您就不再需要生成 SDDL 用的模板文件夹了。您可以将安全信息应用到其它文件系统对象中,例如设置基本 NTFS 权限,或先编辑 SDDL 再应用它。
为您提供一些启示,在域迁移的场景中,您可以比如创建一个转换表,用于将旧的 SID 转换为新的 SID。然后,将旧的 SID 替换成新的 SID,然后将记录下的安全信息克隆到一个新的(或测试的)域中。
适用于 PowerShell 所有版本
以下代码从一个文件夹读取 NTFS 权限并将该设置应用到另外一个文件夹上。请注意两个文件夹都必须存在:
$FolderToCopyFrom = 'C:\folder1'
$FolderToCopyTo = 'C:\folder2'
$securityDescriptor = Get-Acl -Path $FolderToCopyFrom
Set-Acl -Path $FolderToCopyTo -AclObject $securityDescriptor
复制安全描述符操作可能需要管理员权限。请注意第二个文件夹的所有安全规则都会被第一个文件夹的安全信息覆盖。
适用于 PowerShell 所有版本
当您运行本地控制台命令,例如 robocopy.exe
、ipconfig.exe
或类似的命令时,您可以处理这些命令中抛出的错误:
try
{
$current = $ErrorActionPreference
$ErrorActionPreference = 'Stop'
# this will cause an EXE command to emit an error
# (replace with any console-based EXE command)
net.exe user nonexistentUser 2>&1
$ErrorActionPreference = $current
}
catch
{
Write-Host ('Error occured: ' + $_.Exception.Message)
}
要捕获错误,您需要临时将 $ErrorActionPreference
设为“Stop
”。另外,您需要用“2>&1
”将错误信息重定向到输出控制台。
这么做完之后,例如 .NET 错误等错误就可以被 PowerShell 处理了。
适用于 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 所有版本
这个简单的函数可以返回当前系统的启动时间:
function Get-Uptime
{
$millisec = [Environment]::TickCount
[Timespan]::FromMilliseconds($millisec)
}
适用于 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 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