PowerShell 技能连载 - 删除所有指定层级下的子文件夹
以下是另一个听起来复杂,但实际上并没有那么复杂的文件系统任务。假设您需要移除某个文件系统指定层级之下所有文件夹。以下是实现方法:
1 | # Task: |
只需要在路径中使用 “*
“。要删除某个指定路径下的两层之下的目录,相应地做以下调整:
1 | # Task: |
以下是另一个听起来复杂,但实际上并没有那么复杂的文件系统任务。假设您需要移除某个文件系统指定层级之下所有文件夹。以下是实现方法:
1 | # Task: |
只需要在路径中使用 “*
“。要删除某个指定路径下的两层之下的目录,相应地做以下调整:
1 | # Task: |
有些任务听起来复杂,实际上并没有那么复杂。假设我们需要清除一个目录结构,移除所有文件,而留下空白的文件夹。我们进一步假设有一些文件位于白名单上,不应移除。如果用 PowerShell,那么实现起来很容易:
1 | # Task: |
一个新的 PowerShell 后台线程可以在后台工作,例如每 5 秒钟在 PowerShell 窗口标题栏上显示新的 RSS 供稿。
首先,我们先看看如何获取新闻供稿内容:
1 | $RSSFeedUrl = 'https://www.technologyreview.com/stories.rss' |
可以自由调整 RSS 公告的地址。如果修改了地址,请也注意调整 “title
“ 和 “description
“ 属性名。每个 RSS 供稿可以任意命名这些属性。
以下是向标题栏添加新内容的完整解决方案:
1 | $Code = { |
Invoke-WebRequest
只是简单地从任意的网站下载内容。接下来读取内容并分析它,是您的工作。在前一个技能中我们解释了如何下载 PowerShell 代码,并且执行它:
1 | $url = "http://bit.ly/e0Mw9w" |
(请注意:请在 PowerShell 控制台中运行以上代码。如果在 PowerShell ISE 等编辑器中运行,杀毒引擎将会阻止运行)
类似地,如果数据是以 XML 格式返回的,您可以将它转换为 XML。并且做进一步处理,例如从银行获取当前的汇率:
1 | $url = "http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml" |
作为对比,Invoke-RestMethod
不仅仅下载数据,而且遵循数据的类型。您会自动得到正确的数据。以下是上述操作的简化版本,用的是 Invoke-RestMethod
来代替 Invoke-WebRequest
:
调用 Rick-Ascii
(从 PowerShell 控制台运行):
1 | $url = "http://bit.ly/e0Mw9w" |
获取货币汇率:
1 | $url = "http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml" |
在之前的技能中我们介绍了如何用 Invoke-WebRequest
下载任意网页的 HTML 内容。这也可以用来下载 PowerShell 代码。Invoke-WebRequest
可以下载任意 WEB 服务器提供的内容,所以以下示例代码可以下载一段 PowerShell 脚本:
1 | $url = "http://bit.ly/e0Mw9w" |
如果您信任这段代码,您可以方便地下载和运行它:
1 | Invoke-Expression -Command $code |
这段代码适用于 PowerShell 控制台,您将见到一个“跳舞的 Rick Ascii 艺术”并听到有趣的音乐,如果在另一个编辑器中运行以上代码,您的 AV 可能会阻止该调用并且将它识别为一个严重的威胁。这是因为下载的代码会检测它运行的环境,由于它需要在控制台中运行,所以如果在其它地方运行它,将会启动一个 PowerShell 控制台。这个操作是由杀毒引擎控制的,随后会被系统阻止。
有些时候,cmdlet 自动显示一个进度条,以下是一个显示进度条的例子:
1 | $url = "http://www.powertheshell.com/reference/wmireference/root/cimv2/" |
Invoke-WebRequest
获取一个 WEB 页面的原始内容,如果获取内容消耗一定的时间,将会显示进度条。
Whenever you run a cmdlet that shows a progress bar, you can hide the progress bar by temporarily changing the $ProgressPreference variable. Just make sure you restore its original value or else, you permanently hide progress bars for the current PowerShell session:
当您运行一个会显示进度条的 cmdlet,您可以通过临时改变 $ProgressPreference
变量来隐藏进度条。只需要记得恢复它的初始值或是设置成其它值,这样就可以针对当前 PowerShell 会话隐藏进度条。
1 | $old = $ProgressPreference |
除了保存和恢复原始的变量内容,您还可以使用脚本块作用域:
1 | & { |
如您所见,当脚本块执行完之后,原始变量自动恢复原始值。
PowerShell 内置了一个 WEB 客户端,它可以获取 HTML 内容。对于简单的 WEB 页面分析,使用 -UseBasicParsing
参数即可。该操作将原原本本地获取原始的 HTML 内容,例如,包含嵌入的链接和图像的列表:
1 | $url = "http://powershellmagazine.com" |
如果忽略了 -UseBasicParsing
参数,那么该 cmdlet 内部使用 Internet Explorer 文档对象模型,并返回更详细的信息:
1 | $url = "http://powershellmagazine.com" |
请注意 Invoke-WebRequest
需要您实现设置并且至少打开一次 Internet Explorer,除非您指定了 -UseBasicParsing
。
如果您正在编写 PowerShell 函数,并且知道某个函数可能会造成很多危险结果,那么有一个简单的方法可以增加一层额外的安全防护。以下是了个函数,一个没有安全防护,而另一个有安全防护:
1 | function NoSafety |
当您运行 “NoSafety
“,直接运行完毕。而当您运行 “Safety
“,用户会得到一个确认提示,只有确认了该提示,函数才能继续执行。
要实现这个有两个步骤。第一,[CmdletBinding(...)]
语句增加了 WhatIf
和 -Confirm
参数,而 ConfirmImpact="High"
将函数标记为有潜在危险的。
第二,在函数代码中的第一件事情是调用 $PSCmdlet.ShouldProcess
,在其中你可以定义确认信息。如果这个调用返回 $false
,那么代码中的 -not
操作符 (!
) 将抛出结果,而该函数立即返回。
用户仍然可以通过显式关闭确认的方式,不需确认运行该函数:
1 | PS> Safety -Something test -Confirm:$false |
或者,通过设置 $ConfirmPreference
为 “None
“,直接将本 PowerShell 会话中的所有的自动确认对话框关闭:
1 | PS> $ConfirmPreference = "None" |
在前一个技能中我们解释了如何在 IntelliSense 中隐藏参数。今天我们想向您介绍一个很酷的副作用!
PowerShell 支持两种类型的函数:简单函数和高级函数。一个简单的函数只暴露了您定义的参数。高级函数还加入了所有常见的参数。以下是两个示例函数:
1 | function Simple |
当您在编辑器中通过 IntelliSense 调用 Simple
函数,您只能见到 -Name
参数。当您调用 Advanced
函数时,还能看到一系列常见的参数,这些参数总是出现。
当您使用一个属性(属性的模式为 [Name(Value)]
),PowerShell 将创建一个高级函数,并且无法排除通用参数。那么如何既保留高级函数的优点(例如必选参数)但只向用户显示自己的参数呢?
以下是一个秘籍。请对比以下两个函数:
1 | function Advanced |
当调用 “Advanced
“ 函数时,将显示自定义的参数以及通用参数。当对 “AdvancedWithoutCommon
“ 做相同的事时,只会见到自定义的参数但保留高级函数的功能,例如 -Name
参数仍然是必选的。
这种效果是通过添加一个或多个隐藏参数实现的。隐藏参数是从 PowerShell 5 开始引入的,用于加速类方法(禁止显示隐藏属性)。由于类成员不显示通用参数,所以属性值 “DontShow
“ 不仅从 IntelliSense 中隐藏特定的成员,而且隐藏所有通用参数。
这恰好导致另一个有趣的结果:虽然通用参数现在从 IntelliSense 中隐藏,但他们仍然存在并且可使用:
1 | function Test |
在之前的一个技能中我们介绍了如何用 Get-Member
获取对象的属性。以下是另一个可以传入任何对象,将它转为一个包含排序属性的哈希表,然后排除所有空白属性的用例。
1 | # take an object... |