PowerShell 技能连载 - 更新 Windows Defender 病毒定义
Windows 8.1 带来了一系列新的 cmdlet。其中一个可以自动下载并安装 Windows Defender 最新的反病毒定义。
Get-MpComputerStatus
返回当前病毒定义的信息。
这些 cmdlet 不是 PowerShell 的一部分,而是 Windows 8.1 的一部分,所以在早期版本的操作系统中,您会碰到找不到命令的错误信息。
Windows 8.1 带来了一系列新的 cmdlet。其中一个可以自动下载并安装 Windows Defender 最新的反病毒定义。
Get-MpComputerStatus
返回当前病毒定义的信息。
这些 cmdlet 不是 PowerShell 的一部分,而是 Windows 8.1 的一部分,所以在早期版本的操作系统中,您会碰到找不到命令的错误信息。
某些时候,唯一的自动化处理办法是向 UI 组件发送按键和鼠标点击消息。一个强大且免费的 PowerShell 扩展,叫做“WASP”,地址如下:
一旦您装好了这个模块(解压前别忘了解除 ZIP 文件锁定。方法是右键点击,属性,解锁),WASP 模块提供以下 cmdlet:
以下是一个简单的操作 Windows 计算器的例子:
Import-Module WASP
# launch Calculator
$process = Start-Process -FilePath calc -PassThru
$id = $process.Id
Start-Sleep -Seconds 2
$window = Select-Window | Where-Object { $_.ProcessID -eq $id }
# send keys
$window | Send-Keys 123
$window | Send-Keys '{+}'
$window | Send-Keys 999
$window | Send-Keys =
# send CTRL+c
$window | Send-Keys '^c'
# Result is now available from clipboard
以下是附加说明:
CTRL
+C
时,请使用小写字母。“^c
”代表发送 CTRL
+c
,而“^C
”代表发送 CTRL
+SHIFT
+C
。Select-ChildWindow
, Select-Control
)。WPF 窗口也可以接收按键,但是 WPF 中在窗体的 UI 组件之上无法获得支持输入的控件。WPF (Windows Presentation Foundation) 是一种创建窗体和对话框的技术。WPF 的好处是窗体设计和程序代码可以分离。
以下是一个显示醒目消息的例子。消息内容定义在 XAML 代码中,看起来类似 HTML (不过是区分大小写的)。您可以很容易地调整字体大小、文字、颜色等。不需要改任何程序代码:
$xaml = @"
<Window
xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>
<Border BorderThickness="20" BorderBrush="Yellow" CornerRadius="9" Background='Red'>
<StackPanel>
<Label FontSize="50" FontFamily='Stencil' Background='Red' Foreground='White' BorderThickness='0'>
System will be rebooted in 15 minutes!
</Label>
<Label HorizontalAlignment="Center" FontSize="15" FontFamily='Consolas' Background='Red' Foreground='White' BorderThickness='0'>
Worried about losing data? Talk to your friendly help desk representative and freely share your concerns!
</Label>
</StackPanel>
</Border>
</Window>
"@
$reader = [System.XML.XMLReader]::Create([System.IO.StringReader] $xaml)
$window = [System.Windows.Markup.XAMLReader]::Load($reader)
$Window.AllowsTransparency = $True
$window.SizeToContent = 'WidthAndHeight'
$window.ResizeMode = 'NoResize'
$Window.Opacity = .7
$window.Topmost = $true
$window.WindowStartupLocation = 'CenterScreen'
$window.WindowStyle = 'None'
# show message for 5 seconds:
$null = $window.Show()
Start-Sleep -Seconds 5
$window.Close()
您显然可以通过 Send-MailMessage
直接发送邮件。但如果您希望通过缺省的 MAPI 客户端发送电子邮件,也不会太麻烦:
$subject = 'Sending via MAPI client'
$body = 'My Message'
$to = 'tobias@powertheshell.com'
$mail = "mailto:$to&subject=$subject&body=$body"
Start-Process -FilePath $mail
这个脚本利用了 mailto: 语法。如果您已安装了一个 MAPI 客户端,这将打开一个电子邮件表单并且将脚本指定的内容填充进去。不过您需要手工发送邮件。
您机器上的 MAPI 客户端就是处理类似“mailto:” URL 的缺省电子邮件客户端。我们设计一个函数来查找是否有 MAPI 客户端,如果有的话,查看具体是哪一个。该函数从 Windows 注册表中获取这项信息:
function Get-MAPIClient
{
function Remove-Argument
{
param
(
$CommandLine
)
$divider = ' '
if ($CommandLine.StartsWith('"'))
{
$divider = '"'
$CommandLine = $CommandLine.SubString(1)
}
$CommandLine.Split($divider)[0]
}
$path = 'Registry::HKEY_CLASSES_ROOT\mailto\shell\open\command'
# create new object to return values
$returnValue = 1 | Select-Object -Property HasMapiClient, Path, MailTo
$returnValue.hasMAPIClient = Test-Path -Path $path
if ($returnValue.hasMAPIClient)
{
$values = Get-ItemProperty -Path $path
$returnValue.MailTo = $values.'(default)'
$returnValue.Path = Remove-Argument $returnValue.MailTo
if ((Test-Path -Path $returnValue.Path) -eq $false)
{
$returnValue.hasMAPIClient = $true
}
}
$returnValue
}
Get-MAPIClient
以下是使用结果:
在前一个技巧中,我们演示了如何从命令行中提取命令名,并忽略所有参数。今天,您将学习到如何用一个函数同时获取到命令名和参数。该函数将命令行分割为实际的命令名和它的参数,并返回一个自定义对象:
function Get-Argument
{
param
(
$CommandLine
)
$result = 1 | Select-Object -Property Command, Argument
if ($CommandLine.StartsWith('"'))
{
$index = $CommandLine.IndexOf('"', 1)
if ($index -gt 0)
{
$result.Command = $CommandLine.SubString(0, $index).Trim('"')
$result.Argument = $CommandLine.SubString($index+1).Trim()
$result
}
}
else
{
$index = $CommandLine.IndexOf(' ')
if ($index -gt 0)
{
$result.Command = $CommandLine.SubString(0, $index)
$result.Argument = $CommandLine.SubString($index+1).Trim()
$result
}
}
}
Get-Argument -CommandLine 'notepad c:\test'
Get-Argument -CommandLine '"notepad.exe" c:\test'
结果如下:
这是一个实际应用中的例子:它获取所有运行中的进程,并返回每个进程的命令名和参数:
Get-WmiObject -Class Win32_Process |
Where-Object { $_.CommandLine } |
ForEach-Object {
Get-Argument -CommandLine $_.CommandLine
}
以下是结果的样子:
既然命令和参数都分开了,您还可以像这样为信息分组:
Get-WmiObject -Class Win32_Process |
Where-Object { $_.CommandLine } |
ForEach-Object {
Get-Argument -CommandLine $_.CommandLine
} |
Group-Object -Property Command |
Sort-Object -Property Count -Descending |
Out-GridView
有些时候我们需要从命令行提取命令名。以下是实现的方法:
代码如下:
function Remove-Argument
{
param
(
$CommandLine
)
$divider = ' '
if ($CommandLine.StartsWith('"'))
{
$divider = '"'
$CommandLine = $CommandLine.SubString(1)
}
$CommandLine.Split($divider)[0]
}
您也许了解了如何用脚本打开一个 MsgBox 对话框。今天,您将学习如何用一段代码打开一个 MsgBox,同时播放一段随机的音效,吸引用户的注意力并增加趣味性。当用户操作 MsgBox 的时候,音效立即停止:
# find random WAV file in your Windows folder
$randomWAV = Get-ChildItem -Path C:\Windows\Media -Filter *.wav |
Get-Random |
Select-Object -ExpandProperty Fullname
# load Forms assembly to get a MsgBox dialog
Add-Type -AssemblyName System.Windows.Forms
# play random sound until MsgBox is closed
$player = New-Object Media.SoundPlayer $randomWAV
$player.Load();
$player.PlayLooping()
$result = [System.Windows.Forms.MessageBox]::Show("We will reboot your machine now. Ok?", "PowerShell", "YesNo", "Exclamation")
$player.Stop()
在前一个技巧中您学到了如何用 Invoke-WebRequest
从 Google 图片搜索中获取图片链接。Invoke-WebRequest
还可以做更多的东西。它可以获取图片 URL 并下载图片。
以下是具体做法:
$SearchItem = 'PowerShell'
$TargetFolder = 'c:\webpictures'
if ( (Test-Path -Path $TargetFolder) -eq $false) { md $TargetFolder }
explorer.exe $TargetFolder
$url = "https://www.google.com/search?q=$SearchItem&espv=210&es_sm=93&source=lnms&tbm=isch&sa=X&tbm=isch&tbs=isz:lt%2Cislt:2mp"
$browserAgent = 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36'
$page = Invoke-WebRequest -Uri $url -UserAgent $browserAgent
$page.Links |
Where-Object { $_.href -like '*imgres*' } |
ForEach-Object { ($_.href -split 'imgurl=')[-1].Split('&')[0]} |
ForEach-Object {
$file = Split-Path -Path $_ -Leaf
$path = Join-Path -Path $TargetFolder -ChildPath $file
Invoke-WebRequest -Uri $_ -OutFile $path
}
您可以下载所有匹配关键字“PowerShell”的高分辨率的图片到您指定的 $TargetFolder 文件夹中。
当您想从互联网下载信息时,Invoke-WebRequest
是您的好帮手。例如,您可以发送一个请求到 Google 并使用 PowerShell 检验它的结果。
Google 也知道您在这么做,所以当您从 PowerShell 发送一个查询时,Google 返回加密的链接。要获取真实的链接,您需要告诉 Google 您使用的不是 PowerShell 而是一个普通的浏览器。这可以通过设置浏览器代理字符串。
这段脚本输入一个关键字并返回所有符合搜索关键字,并且大于 2 兆像素的所有图片的原始地址:
$SearchItem = 'PowerShell'
$url = "https://www.google.com/search?q=$SearchItem&espv=210&es_sm=93&source=lnms&tbm=isch&sa=X&tbm=isch&tbs=isz:lt%2Cislt:2mp"
$browserAgent = 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36'
$page = Invoke-WebRequest -Uri $url -UserAgent $browserAgent
$page.Links |
Where-Object { $_.href -like '*imgres*' } |
ForEach-Object { ($_.href -split 'imgurl=')[-1].Split('&')[0]}