PowerShell 技能连载 - 从文件中读取系统日志
适用于 PowerShell 所有版本
有些时候,您可能会需要读取已经导出到磁盘上的系统日志文件,或者您希望直接从一个“evtx”格式的文件中读取系统日志。
以下是实现的方法:
$path = "$env:windir\System32\Winevt\Logs\Setup.evtx"
Get-WinEvent -Path $path
适用于 PowerShell 所有版本
有些时候,您可能会需要读取已经导出到磁盘上的系统日志文件,或者您希望直接从一个“evtx”格式的文件中读取系统日志。
以下是实现的方法:
$path = "$env:windir\System32\Winevt\Logs\Setup.evtx"
Get-WinEvent -Path $path
适用于 PowerShell 所有版本
WMI 是一个很棒很强大的技术:只需要指定一个 WMI 类名,您就可以获取该类的所有实体。
PS> Get-WmiObject -Class Win32_BIOS
SMBIOSBIOSVersion : 76CN27WW
Manufacturer : LENOVO
Name : 76CN27WW
SerialNumber : 1006250300406
Version : LENOVO - 1
那么如何知道有哪些 WMI 类呢?以下是一个搜索工具函数:
function Find-WMIClass
{
param
(
[Parameter(Mandatory=$true)]
$SearchTerm = 'Resolution'
)
Get-WmiObject -Class * -List |
Where-Object { $_.Properties.Count -ge 3 } |
Where-Object { $_.Name -notlike 'Win32_Perf*' } |
Where-Object {
$ListOfNames = $_.Properties | Select-Object -ExpandProperty Name
($ListOfNames -like "*$SearchTerm*") -ne $null
} |
Sort-Object -Property Name
}
只需要指定一个搜索条件。该函数将会查找所有属性名中包含搜索条件的 WMI 类(可以用通配符来扩大搜索范围)。
这段代码能搜索属性以“resolution”结尾的 WMI 类:
PS> Find-WMIClass -SearchTerm *resolution
NameSpace: ROOT\cimv2
Name Methods Properties
---- ------- ----------
CIM_CacheMemory {SetPowerState, R... {Access, AdditionalErr...
CIM_CurrentSensor {SetPowerState, R... {Accuracy, Availabilit...
CIM_FlatPanel {SetPowerState, R... {Availability, Caption...
CIM_Memory {SetPowerState, R... {Access, AdditionalErr...
CIM_MonitorResolution {} {Caption, Description,...
CIM_NonVolatileStorage {SetPowerState, R... {Access, AdditionalErr...
CIM_NumericSensor {SetPowerState, R... {Accuracy, Availabilit...
CIM_PCVideoController {SetPowerState, R... {AcceleratorCapabiliti...
CIM_PointingDevice {SetPowerState, R... {Availability, Caption...
CIM_Printer {SetPowerState, R... {Availability, Availab...
CIM_Tachometer {SetPowerState, R... {Accuracy, Availabilit...
CIM_TemperatureSensor {SetPowerState, R... {Accuracy, Availabilit...
CIM_VideoController {SetPowerState, R... {AcceleratorCapabiliti...
CIM_VideoControllerResolution {} {Caption, Description,...
CIM_VolatileStorage {SetPowerState, R... {Access, AdditionalErr...
CIM_VoltageSensor {SetPowerState, R... {Accuracy, Availabilit...
Win32_CacheMemory {SetPowerState, R... {Access, AdditionalErr...
Win32_CurrentProbe {SetPowerState, R... {Accuracy, Availabilit...
Win32_DisplayControllerConfigura... {} {BitsPerPixel, Caption...
Win32_MemoryArray {SetPowerState, R... {Access, AdditionalErr...
Win32_MemoryDevice {SetPowerState, R... {Access, AdditionalErr...
Win32_NetworkAdapterConfiguration {EnableDHCP, Rene... {ArpAlwaysSourceRoute,...
Win32_PointingDevice {SetPowerState, R... {Availability, Caption...
Win32_Printer {SetPowerState, R... {Attributes, Availabil...
Win32_PrinterConfiguration {} {BitsPerPel, Caption, ...
Win32_SMBIOSMemory {SetPowerState, R... {Access, AdditionalErr...
Win32_TemperatureProbe {SetPowerState, R... {Accuracy, Availabilit...
Win32_VideoConfiguration {} {ActualColorResolution...
Win32_VideoController {SetPowerState, R... {AcceleratorCapabiliti...
Win32_VoltageProbe {SetPowerState, R... {Accuracy, Availabilit...
下一步,选择一个类名并观察它的实际数据:
PS> Get-WmiObject -Class CIM_CacheMemory | Select-Object -Property *
适用于 PowerShell 所有版本
大多数时候,PowerShell 不会显示从 cmdlet 中返回的所有信息。相反地,PowerShell 限制了只显示信息中最常见的部分。
PS> Get-WmiObject -Class CIM_CacheMemory
BlockSize : 1024
CacheSpeed :
CacheType : 4
DeviceID : Cache Memory 0
InstalledSize : 32
Level : 3
MaxCacheSize : 32
NumberOfBlocks : 32
Status : OK
(...)
要看到完整的信息,请像这样加一句 Select-Object
语句:
PS> Get-WmiObject -Class CIM_CacheMemory | Select-Object -Property *
PSComputerName : TOBI2
DeviceID : Cache Memory 0
ErrorCorrectType : 5
Availability : 3
Status : OK
StatusInfo : 3
BlockSize : 1024
CacheSpeed :
CacheType : 4
InstalledSize : 32
Level : 3
MaxCacheSize : 32
NumberOfBlocks : 32
WritePolicy : 3
__GENUS : 2
__CLASS : Win32_CacheMemory
__SUPERCLASS : CIM_CacheMemory
__DYNASTY : CIM_ManagedSystemElement
__RELPATH : Win32_CacheMemory.DeviceID="Cache Memory 0"
__PROPERTY_COUNT : 53
__DERIVATION : {CIM_CacheMemory, CIM_Memory, CIM_StorageExtent,
CIM_LogicalDevice...}
__SERVER : TOBI2
__NAMESPACE : root\cimv2
__PATH : \\TOBI2\root\cimv2:Win32_CacheMemory.DeviceID="Cache
Memory 0"
Access :
AdditionalErrorData :
Associativity : 7
Caption : Cache Memory
ConfigManagerErrorCode :
ConfigManagerUserConfig :
CorrectableError :
CreationClassName : Win32_CacheMemory
CurrentSRAM : {5}
Description : Cache Memory
EndingAddress :
ErrorAccess :
ErrorAddress :
ErrorCleared :
ErrorData :
ErrorDataOrder :
ErrorDescription :
ErrorInfo :
ErrorMethodology :
ErrorResolution :
ErrorTime :
ErrorTransferSize :
FlushTimer :
InstallDate :
LastErrorCode :
LineSize :
Location : 0
Name : Cache Memory
OtherErrorDescription :
PNPDeviceID :
PowerManagementCapabilities :
PowerManagementSupported :
Purpose : L1 Cache
ReadPolicy :
ReplacementPolicy :
StartingAddress :
SupportedSRAM : {5}
SystemCreationClassName : Win32_ComputerSystem
SystemLevelAddress :
SystemName : TOBI2
Scope : System.Management.ManagementScope
Path : \\TOBI2\root\cimv2:Win32_CacheMemory.DeviceID="Cache
Memory 0"
Options : System.Management.ObjectGetOptions
ClassPath : \\TOBI2\root\cimv2:Win32_CacheMemory
Properties : {Access, AdditionalErrorData, Associativity,
Availability...}
SystemProperties : {__GENUS, __CLASS, __SUPERCLASS, __DYNASTY...}
Qualifiers : {dynamic, Locale, provider, UUID}
Site :
Container :
(...)
适用于 PowerShell 所有版本
是否曾需要查找某个(美国)城市的邮政编码,或者反过来通过邮政编码查找城市的名称?
只需要简单地用 PowerShell 连接到一个免费的 Web Service 就可以获得这些信息:
$webservice = New-WebServiceProxy -Uri 'http://www.webservicex.net/uszip.asmx?WSDL'
$webservice.GetInfoByCity('New York').Table
$webservice.GetInfoByZIP('10286').Table
适用于 PowerShell 所有版本
读取所有注册表信息时,如果您不需要数据类型信息,那么十分简单:只需要用 Get-ItemProperty
即可:
Get-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
如果您确实需要数据类新信息,那么需要做点额外的事情:
$key = Get-Item -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
$key.GetValueNames() |
ForEach-Object {
$ValueName = $_
$rv = 1 | Select-Object -Property Name, Type, Value
$rv.Name = $ValueName
$rv.Type = $key.GetValueKind($ValueName)
$rv.Value = $key.GetValue($ValueName)
$rv
}
适用于 PowerShell 所有版本
当您使用 Get-ChildItem
在目录中递归查找文件时,您有时候会遇到一些权限不足的文件夹。为了禁止错误信息,您可能会使用 -ErrorAction SilentlyContinue
的方法。
这是个不错的实践,但是您也许还希望得到一份权限不足的文件夹的清单。
以下是一段在 Windows 文件夹中搜索所有 PowerShell 脚本的脚本。它将这些文件保存在 $PSScripts
变量中。同时,它将所有的错误信息记录在 $ErrorList
变量中,并列出所有不可存取的文件夹。
$PSScripts = Get-ChildItem -Path c:\windows -Filter *.ps1 -Recurse -ErrorAction SilentlyContinue -ErrorVariable ErrorList
$ErrorList | ForEach-Object {
Write-Warning ('Access denied: ' + $_.CategoryInfo.TargetName)
}
适用于 PowerShell 所有版本
当您从 PowerShell cmdlet 中获取结果时,返回的结果都是包含属性的对象。有些属性是可改变的,另一些是只读的。
以下是一个获取可改变的属性的简单技巧。这段代码是以当前 PowerShell 宿主的进程对象为例,但您可以用任意的 cmdlet 结果。
$myProcess = Get-Process -Id $Pid
$myProcess |
Get-Member -MemberType Properties |
Out-String -Stream |
Where-Object { $_ -like '*set;*' }
结果类似如下:
EnableRaisingEvents Property bool EnableRaisingEvents {get;set;}
MaxWorkingSet Property System.IntPtr MaxWorkingSet {get;set;}
MinWorkingSet Property System.IntPtr MinWorkingSet {get;set;}
PriorityBoostEnabled Property bool PriorityBoostEnabled {get;set;}
适用于 PowerShell ISE 3 或更高版本
出于写文档等目的,您可能需要获得一份 PowerShell 脚本用到的所有变量的清单。
以下是一个名为 Get-Variable
的函数:
function Get-Variable
{
$token = $null
$errors = $null
$ast = [System.Management.Automation.Language.Parser]::ParseInput($psise.CurrentFile.Editor.Text, [ref] $token, [ref] $errors)
# not complete, add variables you want to exclude from the list:
$systemVariables = '_', 'null', 'psitem', 'true', 'false', 'args', 'host'
$null = $ast.FindAll({ $args[0] -is [System.Management.Automation.Language.CommandAst] }, $true)
$token |
Where-Object { $_.Kind -eq 'Variable'} |
Select-Object -ExpandProperty Name |
Where-Object { $systemVariables -notcontains $_ } |
Sort-Object -Unique
}
只需要用系统自带的 ISE 编辑器打开这个脚本,然后在交互式控制台中运行 Get-Variable
。
您将会得到一个排序过的列表,内容是当前打开的脚本用到的所有变量。
如果您将“$psise.CurrentFile.Editor.Text
”替换成一个包含脚本代码的变量,那么您可以在 ISE 编辑器之外运行这个函数。只需要用 Get-Content
将任意脚本的内容读取进一个变量,然后就可以在上述代码中使用这个变量。
适用于 PowerShell ISE 3 或更高版本
以下是一个简单的变量重命名函数,您可以在 PowerShell 3.0 及以上版本的 ISE 编辑器中使用它
它将识别某个变量的所有实例,然后将它重命名为一个新的名字。
function Rename-Variable
{
param
(
[Parameter(Mandatory=$true)]
$OldName,
[Parameter(Mandatory=$true)]
$NewName
)
$InputText = $psise.CurrentFile.Editor.Text
$token = $null
$errors = $null
$ast = [System.Management.Automation.Language.Parser]::ParseInput($InputText, [ref] $token, [ref] $errors)
$token |
Where-Object { $_.Kind -eq 'Variable'} |
Where-Object { $_.Name -eq $OldName } |
Sort-Object { $_.Extent.StartOffset } -Descending |
ForEach-Object {
$start = $_.Extent.StartOffset + 1
$end = $_.Extent.EndOffset
$InputText = $InputText.Remove($start, $end-$start).Insert($start, $NewName)
}
$psise.CurrentFile.Editor.Text = $InputText
}
运行这个函数之后,您将得到一个名为 Rename-Variable
的新命令。
下一步,在 ISE 编辑器中打开一个脚本,然后在控制台面板中,键入以下内容(当然,需要将旧的变量名“_oldVariableName_”改为您当前所打开的 ISE 脚本中实际存在的变量名)。
PS> Rename-Variable -OldName oldVariableName -NewName theNEWname
立刻,旧变量的所有出现的地方都被替换成新的变量名。
注意:这是一个非常简易的变量重命名函数。一定要记得备份您的脚本。它还不能算是一个能用在生产环境的重构方案。
当您重命名变量时,您脚本的许多别处地方也可能需要更新。例如,当一个变量是函数参数时,所有调用该函数的地方都得修改它们的参数名。
适用于 PowerShell 所有版本
当您从 Internet 中下载了文件之后,您也许会遇到文件无法在编辑器中正常打开的情况。最常见的是,由于非正常行尾符导致的。
以下是这个问题的一个例子。在前一个技能里我们演示了如何下载一份 MAC 地址的厂家清单。当下载完成后用记事本打开它时,换行都消失了:
$url = 'http://standards.ieee.org/develop/regauth/oui/oui.txt'
$outfile = "$home\vendorlist.txt"
Invoke-WebRequest -Uri $url -OutFile $outfile
Invoke-Item -Path $outfile
要修复这个文件,只需要使用这段代码:
$OldFile = "$home\vendorlist.txt"
$NewFile = "$home\vendorlistGood.txt"
Get-Content $OldFile | Set-Content -Path $NewFile
notepad $NewFile
Get-Content
能够检测非标准的行尾符,所以结果是各行的字符串数组。当您将这些行写入一个新文件时,一切都会变正常,因为 Set-Content
会使用缺省的行尾符。