PowerShell 技能连载 - 监测日志文件

从 PowerShell 3.0 开始,实时监测基于文本的日志文件变得很容易。试试以下代码:

$Path = "$home\Desktop\testfile.txt"

'Test' | Out-File "$home\Desktop\testfile.txt"
notepad $Path

Get-Content -Path $Path -Tail 0 -Wait | Out-GridView -Title $Path

这段代码将在桌面上创建一个文本文件,然后在记事本中打开它。然后 PowerShell 将开始监视文件的变化。一旦您向记事本窗口键入新的文本并保存,则变化的部分会呈现在 PowerShell 的网格视图中。

要监视另一个基于文本的日志文件,只需要改变路径参数即可。由于 PowerShell 在监视文件的状态下处于阻塞状态,您可能需要在另一个 PowerShell 实例中执行新的代码。

译者注:Get-Content -Tail 的效果和 Linux 下的 tail -f 命令的执行效果一致。但 PowerShell 是面向 .NET 对象的,可以利用管道和其它命令,例如 Out-GridView 配合,更为强大。

快速生成树形结构的纯文本

今天帮朋友整理一些材料,需要为这些材料整理一个目录。之前有研究过一些方案,例如:

这些方案有一个共性:麻烦。也就是无法像手头的工具一样拿来就用。于是发掘了一番,发现 tree 这个 dos 时代的命令刚好能满足需要。该命令的帮助如下:

以图形显示驱动器或路径的文件夹结构。

TREE [drive:][path] [/F] [/A]

   /F   显示每个文件夹中文件的名称。
   /A   使用 ASCII 字符,而不使用扩展字符。

我们可以用以下命令将 D:\work 下的结构输出到 output.txt 文本文件:

TREE "D:\work" /F /A > output.txt

然后用记事本之类的文本编辑器对它进行简单的编辑,就可以达到目的。

还可以拓展一下思路:在撰写文章的时候,常常需要描述一个有层次的结构(可以是心得体会之类的,不仅限于描述一系列文件)。此时可以在硬盘里创建一个临时目录,在里面创建一些文件夹和文件,用资源管理器拖拽调整目录结构,然后用上述命令导出一个目录文件,就可以快速地用于文档的撰写了。请不要徒手编辑这样的文本,因为那样很愚蠢,调整起来也相当费功夫。

命令执行效果参考:

卷 os 的文件夹 PATH 列表
卷序列号为 0000002C 000E:BD6F
C:.
|   HaxLogs.log
|   setmockup.log
|   WEVTUTIL.exe
|
+---adt-bundle-windows-x86
|   |   SDK Manager.exe
|   |
|   +---android-ndk-r9
|   |   |   documentation.html
|   |   |   GNUmakefile
...
|   |   |   README.TXT
|   |   |   RELEASE.TXT
|   |   |
|   |   +---build
|   |   |   +---awk
|   |   |   |       check-awk.awk
|   |   |   |       extract-debuggable.awk

PowerShell 技能连载 - 按 F1 跳转到 PowerShell 帮助主题

要在 PowerShell 3.0 ISE 编辑器中获得 PowerShell 所有类型的操作符帮助信息,首先列出关于操作符的所有帮助主题:

help operators

您将会见到一个类似这样的列表:

PS> help operators

Name                              Category  Module                    Synopsis
----                              --------  ------                    --------
about_Arithmetic_Operators        HelpFile                            SHORT DESCRIPTION
about_Assignment_Operators        HelpFile                            SHORT DESCRIPTION
about_Comparison_Operators        HelpFile                            SHORT DESCRIPTION
about_Logical_Operators           HelpFile                            SHORT DESCRIPTION
about_Operators                   HelpFile                            SHORT DESCRIPTION
about_Type_Operators              HelpFile                            SHORT DESCRIPTION

如果您没有看见这个列表,您也许需要先下载 PowerShell 帮助文档。请通过 Update-Help 来查看方法!

然后,单击其中的任意一个主题,然后按下 F1 键。帮助窗口将会打开,并显示详细的帮助。

PowerShell 技能连载 - 键盘技巧

在 PowerShell ISE 4.0 控制台窗格中,按住 CTRL 键,然后按 向上 键,可以将光标从命令行中移到结果区域中。

PowerShell 技能连载 - 查找缺少邮箱地址的 Active Directory 用户

LDAP 查询的功能非常强大,可以帮助查找缺少信息的账户。

这段代码将返回所有带邮箱地址的 Active Directory 用户:

$searcher = [ADSISearcher]"(&(sAMAccountType=$(0x30000000))(mail=*))"
$searcher.FindAll() |
  ForEach-Object { $_.GetDirectoryEntry() } |
  Select-Object -Property sAMAccountName, name, mail

如果您想查询相反的内容,请通过“!”号进行相反的查询。以下代码可以返回所有缺少邮箱地址的 Active Directory 用户:

$searcher = [ADSISearcher]"(&(sAMAccountType=$(0x30000000))(!(mail=*)))"
$searcher.FindAll() |
  ForEach-Object { $_.GetDirectoryEntry() } |
  Select-Object -Property sAMAccountName, name, mail

用 PowerShell 脚本获取天气实况

只要两行命令,就可以“轻松”地获取实时天气预报:

(curl http://61.4.185.48:81/g/ -UseBasicParsing).Content -cmatch 'var id=(\d+);' | Out-Null
irm "http://www.weather.com.cn/data/sk/$($matches[1]).html" | select -exp weatherinfo

使用效果:

PS >(curl http://61.4.185.48:81/g/ -UseBasicParsing).Content -cmatch 'var id=(\d+);' | Out-Null
PS >irm "http://www.weather.com.cn/data/sk/$($matches[1]).html" | select -exp weatherinfo


city    : 福州
cityid  : 101230101
temp    : 15
WD      : 北风
WS      : 2级
SD      : 79%
WSE     : 2
time    : 10:20
isRadar : 1
Radar   : JC_RADAR_AZ9591_JB

您还可以把第二行改为以下形式,获取更猛的数据:

irm "http://m.weather.com.cn/data/$($matches[1]).html" | select -exp weatherinfo

或:

irm "http://www.weather.com.cn/data/cityinfo/$($matches[1]).html" | select -exp weatherinfo

源代码下载

顺便透露一下,高富帅一般不这么看天气预报哦!

PowerShell 技能月刊

编号 发布时间 标题 PDF
Vol.01 2013年06月 文件系统任务 下载
Vol.02 2013年07月 数组和哈希表 下载
Vol.03 2013年08月 日期、时间和文化 下载
Vol.04 2013年09月 对象和类型 下载
Vol.05 2013年10月 WMI 下载
Vol.06 2013年11月 正则表达式 下载
Vol.07 2013年12月 函数 下载
Vol.08 2013年12月 静态 .NET 方法 下载
Vol.09 2014年01月 注册表 下载
Vol.10 2014年02月 Internet 相关任务 下载
Vol.11 2014年03月 XML 相关任务 下载
Vol.12 2014年08月 安全相关任务 下载

如果您(和我一样)足够懒,也可以用这样一行 PowerShell 代码来下载:

1..12 | ForEach-Object { Invoke-WebRequest "http://powershell.com/cs/PowerTips_Monthly_Volume_$_.pdf" -OutFile "PowerTips_Monthly_Volume_$_.pdf" }

PowerShell 技能连载 - 自动找借口的脚本

译者注:您没有看错!这是近期最邪恶的一个技巧,文末有译者机器上的实验效果。

厌倦了每次自己想蹩脚的借口?以下脚本能让您每调用一次 Get-Excuse 就得到一个新的接口!您所需的一切只是 Internet 连接:

function Get-Excuse
{
  $url = 'http://pages.cs.wisc.edu/~ballard/bofh/bofhserver.pl'
  $ProgressPreference = 'SilentlyContinue'
  $page = Invoke-WebRequest -Uri $url -UseBasicParsing
  $pattern = '<br><font size = "\+2">(.+)'

  if ($page.Content -match $pattern)
  {
    $matches[1]
  }
}

如果您需要通过代理服务器或者身份认证来访问 Internet,那么请查看函数中 Invoke-WebRequest 的参数。您可以通过它提交代理服务器信息,例如身份验证信息。

译者注:以下是 Get-Excuse 为笔者找的“借口”,很有创意吧 ;-)

PS >Get-Excuse
your process is not ISO 9000 compliant
PS >Get-Excuse
evil hackers from Serbia.
PS >Get-Excuse
piezo-electric interference
PS >Get-Excuse
Bogon emissions
PS >Get-Excuse
because Bill Gates is a Jehovah's witness and so nothing can work on St. Swithin's day.
PS >Get-Excuse
Your cat tried to eat the mouse.
PS >Get-Excuse
It works the way the Wang did, what's the problem
PS >Get-Excuse
Telecommunications is upgrading.
PS >Get-Excuse
Your computer's union contract is set to expire at midnight.
PS >Get-Excuse
Daemon escaped from pentagram
PS >Get-Excuse
nesting roaches shorted out the ether cable
PS >Get-Excuse
We ran out of dial tone and we're and waiting for the phone company to deliver another bottle.
PS >Get-Excuse
Root nameservers are out of sync

PowerShell 技能连载 - 导出和导入 PowerShell 历史

PowerShell 保存了您键入的所有命令列表,但是当您关闭 PowerShell 时,这个列表就丢失了。

以下是一个保存当前命令历史到文件的单行代码:

Get-History | Export-Clixml $env:temp\myHistory.xml

当您启动一个新的 PowerShell 控制台或 ISE 编辑器实例时,您可以将保存的历史读入 PowerShell:

Import-Clixml $env:\temp\myHistory.xml | Add-History

不过,加载历史并不会影响键盘缓冲区,所以按下上下键并不会显示新导入的历史条目。然而,您可以用 TAB 自动完成功能来查找您之前输入的命令:

#(KEYWORD) <-现在按下(TAB)键!

在 PowerShell 脚本中使用 C# 代码

PowerShell 使我们拥有了一门非常强大的脚本语言。许多产品,例如 SharePoint 以 Cmdlet 的形式提供了它们自己的管理扩展。

客户们喜欢脚本语言,是因为它使他们能够编写自己的代码而不需要运行某个编译器,也不需要将可执行程序拷贝到它们的目标计算机中。相对于部署一个脚本,在那些目标计算机中运行一个可执行程序或者在命令行 Shell 中执行一些命令通常需要更复杂的审批过程。

但是从另一方面来说,编写 PowerShell 脚本需要学习一门新的脚本语言并且需要使用他们所熟悉范围之外的工具。作为一个开发者,我喜欢 C# 和 Visual Studio 的智能提示等强大功能。并且,在过去几年内,我用 C# 开发了许多工具——并且我不希望在移植到 PowerShell 的过程中丢弃这些设计好的轮子。

所以如果能在 PowerShell 中复用现有的 C# 代码,而不需要将它以 Cmdlet的形式实现的话,那就十分理想了。

实际上 PowerShell 2.0 提供了一种方式来实现它:使用 Add-Type Cmdlet,它能够通过您提供的 C# 源代码在内存中生成一个新的 .NET 程序集,并且可以将该程序集直接用于同一个会话中的 PowerShell 脚本中。

出于演示的目的,我们假设已有以下简单的 C# 代码,作用是获取和设置 SharePoint 中的 Content Deployment 的 RemoteTimeout 值:

using Microsoft.SharePoint.Publishing.Administration;
using System;

namespace StefanG.Tools
{
    public static class CDRemoteTimeout
    {
        public static void Get()
        {
            ContentDeploymentConfiguration cdconfig = ContentDeploymentConfiguration.GetInstance();
            Console.WriteLine("Remote Timeout: "+cdconfig.RemoteTimeout);
        }

        public static void Set(int seconds)
        {
            ContentDeploymentConfiguration cdconfig = ContentDeploymentConfiguration.GetInstance();
            cdconfig.RemoteTimeout = seconds;
            cdconfig.Update();
        }
    }
}

除了引用 .NET 框架之外,这个工具还引用了两个 SharePoint DLL(Microsoft.SharePoint.dllMicrosoft.SharePoint.Publishing.dll),它们用来存取 SharePoint 的对象模型。为了确保 PowerShell 能正确地生成程序集,我们需要为 Add-Type Cmdlet 用 -ReferencedAssemblies 参数提供引用信息。

为了指定源代码的语言(可以使用 CSharpCSharpVersion3Visual BasicJScript),您需要使用 -Language 参数。缺省值是 CSharp

在我的系统中我有一个 csharptemplate.ps1[csharptemplate.ps1] 文件,我可以快速地复制和修改成我需要的样子来运行我的 C# 代码:

$Assem = (
...add referenced assemblies here...
    )

$Source = @"
...add C# source code here...
"@

Add-Type -ReferencedAssemblies $Assem -TypeDefinition $Source -Language CSharp

对于上述的 C# 例子,对应的最终 PowerShell 脚本如下:

$Assem = (
    "Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" ,
    "Microsoft.SharePoint.Publishing, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
    )

$Source = @"
using Microsoft.SharePoint.Publishing.Administration;
using System;

namespace StefanG.Tools
{
    public static class CDRemoteTimeout
    {
        public static void Get()
        {
            ContentDeploymentConfiguration cdconfig = ContentDeploymentConfiguration.GetInstance();
            Console.WriteLine("Remote Timeout: "+cdconfig.RemoteTimeout);
        }

        public static void Set(int seconds)
        {
            ContentDeploymentConfiguration cdconfig = ContentDeploymentConfiguration.GetInstance();
            cdconfig.RemoteTimeout = seconds;
            cdconfig.Update();
        }
    }
}
"@

Add-Type -ReferencedAssemblies $Assem -TypeDefinition $Source -Language CSharp

[StefanG.Tools.CDRemoteTimeout]::Get()
[StefanG.Tools.CDRemoteTimeout]::Set(600)

上述例子的最后几行演示了如何在 PowerShell 中调用 C# 方法。

注:文中涉及到的 csharptemplate.ps1 可以在这里[下载][csharptemplate.ps1]。
[csharptemplate.ps1]: /assets/download/csharptemplate.ps1