PowerShell 技能连载 - 查找所有用户脚本

有些时候我们会疑惑当 PowerShell 启动的时候,将执行哪些启动脚本。它们数量很多,而且各不相同,要看您运行的是 PowerShell 控制台,ISE,还是其他宿主。

然而,了解您的用户脚本是十分重要的。它们决定了应用到 PowerShell 环境的配置。

这个 Get-PSProfileStatus 函数列出了所有宿主(PowerShell 环境)可能用到的的启动脚本。它也显示了哪些脚本是物理存在的。

function Get-PSProfileStatus
{
    $profile |
      Get-Member -MemberType NoteProperty |
      Select-Object -ExpandProperty Name |
      ForEach-Object {
        $_, (Split-Path $profile.$_ -Leaf), (Split-Path $profile.$_),
                              (Test-Path -Path $profile.$_) -join ',' |
          ConvertFrom-Csv -Header Profile, FileName, FolderName, Present
        }
}

Get-PSProfileStatus

结果看起来类似这样:

将结果用管道输出到 Out-GridView 来查看,避免截断字符被截断:

Get-PSProfileStatus | Out-GridView
评论

PowerShell 技能连载 - 通过CSV创建对象

有多种方法可以创建自定义对象。以下是一种创新的办法,在很多种场景中都很有效:创建一个逗号分隔,每行表示一个值的列表文本,然后用 ConvertFrom-Csv 来创建对象:

for($x=0; $x -lt 20; $x++)
{
    ($x,(Get-Random),(Get-Date) -join ',') | ConvertFrom-Csv -Header ID, RandomNumber, Date
}

不过,这种做法效率并不是很高。还有三种其它方法可以用来创建对象。分别用 Measure-Command 测量创建 2000 个对象所消耗的时间:

Measure-Command {
    for($x=0; $x -lt 2000; $x++)
    {
        ($x,(Get-Random),(Get-Date) -join ',') | ConvertFrom-Csv -Header ID, RandomNumber, Date
    }
}

Measure-Command {
    for($x=0; $x -lt 2000; $x++)
    {
        $obj = 1 | Select-Object -Property ID, RandomNumber, Date
        $obj.ID = $x
        $obj.RandomNumber = Get-Random
        $obj.Date = Get-Date
        $obj
    }
}

Measure-Command {
    for($x=0; $x -lt 2000; $x++)
    {
        [PSObject]@{
            ID = $x
            RandomNumber = Get-Random
            Date = Get-Date
        }
    }
}

Measure-Command {
    for($x=0; $x -lt 2000; $x++)
    {
        [Ordered]@{
            ID = $x
            RandomNumber = Get-Random
            Date = Get-Date
        }
    }
}

如结果所示,最后两种方法的效率是 CSV 方法的大约三倍。在我们的测试系统上,所有的测试都在一秒之内完成,所以现实环境中影响并不大。

请挑选一个您自己最喜欢的方式——不过请注意最后一个例子需要 PowerShell 3.0 或更高的版本。

评论

PowerShell 技能连载 - 通过关键词查找脚本

随着您硬盘上的 PowerShell 脚本数量的增多,要想找到您想要的脚本会变得越来越困难。以下是一个叫做 Find-Script 的工具函数。只要传入一个关键词,PowerShell 将会在您的个人文件夹下找出所有包含该关键词的脚本。

查找的结果将在一个 GridView 窗口中显示,您可以选中其中的文件,按下确认按钮以后将用 ISE 编辑器打开这些文件。

function Find-Script
{
    param
    (
        [Parameter(Mandatory=$true)]
        $Keyword,

        $Maximum = 20,
        $StartPath = $env:USERPROFILE
    )

    Get-ChildItem -Path $StartPath -Filter *.ps1 -Recurse -ErrorAction SilentlyContinue |
      Select-String -SimpleMatch -Pattern $Keyword -List |
      Select-Object -Property FileName, Path, Line -First $Maximum |
      Out-GridView -Title 'Select Script File' -PassThru |
      ForEach-Object { ise $_.Path }
}

默认情况下,Find-Script 只返回满足搜索条件的前 20 个脚本。您可以通过 -Maximum-StartPath 参数来改变最大搜索条数和搜索位置。

评论

在PowerShell中操作Word - 使用格式化样式

在这个系列的上一步中,我们演示了用Windows PowerShell创建Microsoft Word文档的基本步骤。如果您试用了我的示例脚本,您会注意到文档格式化方面略有不足。幸运的是,我们有一些简洁的办法来改进您文档的质量,我将会在这篇文章中向您演示这个过程。我们将用第一部分的脚本作为起点。

关键之处在于 Selection 对象。

PS C:\>$word=new-object -ComObject "Word.Application"
PS C:\>$doc=$word.documents.Add()
PS C:\> $selection=$word.Selection

您可以更改 Selection 对象的一个重要元素是 Font。您可以轻松地修改字体大小和颜色,以及使用哪种字体。我将把日期和时间的字体改为绿色。

PS C:\> $selection.Font.Color="wdColorGreen"
PS C:\> $selection.TypeText((Get-Date))

在VBScript的年代中,我们需要定义 wdColorGreen 的值并将它赋给一个常量。但是在PowerShell中我们可以轻松地以字符串的形式插入这个常量。您一定很好奇有哪些颜色可以使用?问问PowerShell吧:

PS C:\> [enum]::GetNames([microsoft.office.interop.word.wdcolor])

您需要把字体颜色改回来,除非您需要把整个文档设为这个颜色。

PS C:\ >$selection.font.Color="wdColorAutomatic"
PS C:\> $selection.TypeParagraph()

在我原先的脚本中我插入了一个标题。现在我们把它变成大一点的字体。我将用我上次使用的WMI代码。

$selection.Font.Size=12
$selection.TypeText("Operating System Information for $($os.CSName)")

回顾一下前面一篇文章,有一个问题是PowerShell输出到Word早期是用等宽字体而后来用的是非等宽字体。解决方法是从PowerShell中插入结果之前指定一个合适的字体。

PS C:\> $selection.Font.Size=10
PS C:\> $selection.Font.Name="Consolas"
PS C:\> $selection.TypeText(($os | Select -Property $props | Out-String))

还要做的最后一件事是添加一段格式化的文本,说明报告的创建者。我希望采用Word的斜体格式来呈现。

PS C:\> $selection.Font.size=8
PS C:\> $selection.Font.Name="Calibri"
PS C:\> $selection.Font.Italic=$True
PS C:\> $by="Report created by $env:userdomain\$env:username"
PS C:\> $selection.TypeText($by)

我相信您一定也掌握了如何使文本变成粗体。

除了指定字体之外,您还可以采用Word内置的样式。

$selection.Style="Title"
$selection.TypeText("Operating System Report")
$selection.TypeParagraph()

您可以用PowerShell查询 Document 对象,看看有哪些样式可以用。

$doc.Styles | select NameLocal

大多数这些样式只能应用在文本的第一行,不过您也可以自己做实验调整一下。

通过这些步骤您可以简洁地通过您的PowerShell脚本创建一个漂亮的Word文档。请下载版本修订过的脚本,New-WordDoc2,并且自己做一下实验。

用PowerShell操作Office系列文章

评论

Visual Studio的PowerShell扩展工具

Visual Studio的PowerShell扩展工具为Visual Studio 2012和2013 RC增加了PowerShell语言支持。

本工具目前为BETA版。

下载地址:Visual Studio工具库
开源项目:GitHub

必须条件:

编辑器扩展

语法高亮、智能感知和代码折叠

Syntax highlighting, IntelliSense and code folding

方法导航

Function navigation

调试器扩展

脚本输出

Script Output

断点支持

Breakpoint Support

本地变量支持

Locals Support

调用堆栈支持

Stack Frame Support

工程系统支持

Project System Support

评论

在PowerShell中操作Word - 生成文档

我假设许多读者用PowerShell生成服务器、事件以及Windows网络上各种数据的报表。您也许创建过纯文本文件,甚至漂亮的HTML报表。但是您也可以用上Microsoft Word,当然,前提是您已经安装了Word。在这个系列的第二部分,我将会向您演示如何用PowerShell为Word文档套用样式

创建Word应用程序对象

PowerShell可以通过COM接口控制Word应用程序。有趣的地方是,虽然您可以交互式地做所有的操作,但我希望您最终能够用脚本操作一切。我们从创建一个Word程序对象开始。

PS C:\> $word=new-object -ComObject "Word.Application"

如果您好奇的话,可以将这个对象输出到 Get-Member 命令。我们将创建一系列对象,您可以将每一个对象通过管道输出到 Get-Member 来探索它们。

下一步,我们创建一个文档对象。

PS C:\> $doc=$word.documents.Add()

现在,Word程序已经启动,并且创建了一个新文档,但是您在屏幕上看不到任何东西。通常这是正常的,因为我们需要它在后台运行。但是如果您想查看所创建的文档,您需要将应用程序的 Visible 属性设置为 True

PS C:\> $word.Visible=$True

在我们插入文本之前,我们需要获取焦点。创建一个 Selection 对象可以帮我们做一些诸如设置字体大小和颜色等操作,我们将在第二部分介绍这些操作。

PS C:\> $selection=$word.Selection

用PowerShell在文档中插入文本

现在光标在文档的顶部,现在可以开始插入文本了。我们将用 Selection 对象的 TypeText() 方法插入当前的日期和时间。

PS C:\> $selection.TypeText((Get-Date))

如果我们继续插入文本,那么文本将会紧挨在日期的后面。现在我们用 TypeParagraph() 方法插入一个回车符。

PS C:\> $selection.TypeParagraph()

让我们继续插入一些文本。我将用WMI获取本地计算机的操作系统信息。

PS C:\> $os=Get-WmiObject -class win32_OperatingSystem
PS C:\> $selection.TypeText("Operating System Information for $($os.CSName)")

由于我希望写入所有的非系统属性,所以我将快速递创建一个数组用来保存所有的属性名。

PS C:\> $os.properties | select Name | foreach -begin {$props=@()} -proc {$props+="$($_.name)"}

现在我可以从 $os 获取所有的属性并插入Word文档。很重要的一点是 TypeText() 的值是字符串型的,所以我需要将内联的PowerShell表达式通过管道输出到 Out-String

PS C:\> $selection.TypeText(($os | Select -Property $props | Out-String))

如果需要的话,还可以继续插入文字和图片。当完成操作以后,我将保存并关闭文档。

PS C:\> $doc.SaveAs([ref]"c:\work\osreport.docx")
PS C:\> $doc.Close()

请确认使用 [ref] 为文件路径转换数据类型。假设我不再创建新的文档,那么剩下的就是关闭Word应用程序。

PS C:\> $word.quit()

这些就是要做的所有事情。最终生成的Word文档是可用的,虽然可能不太漂亮。在我的例子中发现一个问题:Word用的事非等宽字体,而PowerShell的输出格式假设用的是等宽字体。(译者注:可能会造成输出的结果对不整齐)。在第二部分,我将向您演示如何解决这些问题。同时,欢迎下载示例脚本 New-WordDoc.ps1

用PowerShell操作Office系列文章

评论

PowerShell 技能连载 - 设置显示器亮度

如果您的显示驱动程序支持WMI,那么您可以用PowerShell改变显示器的亮度——甚至是远程的计算机!

以下是实现改变显示器亮度的函数:

function Set-MonitorBrightness
{
    param
    (
        [Parameter(Mandatory=$true)]
        [Int][ValidateRange(0,100)]
        $Value,

        $ComputerName,
        $Credential
    )

    $null = $PSBoundParameters.Remove('Value')

    $helper = Get-WmiObject -Namespace root/WMI -Class WmiMonitorBrightnessMethods @PSBoundParameters
    $helper.WmiSetBrightness(1, $Value)
}

只需要指定一个0-100之间的值,您就可以看到显示器亮度发生改变。为 -ComputerName 参数指定远程计算机名或IP地址(均支持多个),然后您远程的同事们会惊讶地发现去吃午餐的时候显示器都变暗了!当然,远程操作WMI需要本地管理员权限,并且为防火墙设置了允许远程管理的规则。

如果提示“不支持”的错误提示信息,那么说明您的显示驱动程序不支持WMI。

这是“有趣”的部分:模拟一个古怪的显示效果:

for($x=0; $x -lt 20; $x++)
{
    Set-MonitorBrightness -Value (Get-Random -Minimum 20 -Maximum 101)
    Start-Sleep -Seconds 1
}
评论

PowerShell 技能连载 - 检测显示器亮度

如果您想检查您当前的显示器亮度(当然,尤其是针对笔记本电脑),以下是一个快捷的函数:

function Get-MonitorBrightness
{
    param($ComputerName, $Credential)

    Get-WmiObject -Namespace root/WMI -Class WmiMonitorBrightness @PSBoundParameters |
        Select-Object -Property PSComputerName, CurrentBrightness, Levels
}

它甚至支持 -ComputerName-Credential,所以您也可以查询远程的主机。

如果您为 -ComputerName 参数传入一个用逗号分隔的主机名或IP地址列表,您将获得所有具有local Admin权限的主机的执行结果。

评论

PowerShell 技能连载 - 创建符号链接

符号链接使用起来很像“普通”的链接文件(*.lnk):它们可以虚拟地指向任何文件或者文件夹,甚至UNC路径。和lnk文件不同的是,创建符号链接需要完整管理员权限,并且用户不可以存取符号链接属性。

以下是一个创建符号链接的函数:

function New-SymbolicLink
{
    param
    (
        [Parameter(Mandatory=$true)]
        $OriginalPath,

        [Parameter(Mandatory=$true)]
        $MirroredPath,

        [ValidateSet('File', 'Directory')]
        $Type='File'
    )

    if(!([bool]((whoami /groups) -match "S-1-16-12288") ))
    {
        Write-Warning 'Must be an admin'
        break
    }
    $signature = '
        [DllImport("kernel32.dll")]
        public static extern bool CreateSymbolicLink(string lpSymlinkFileName, string lpTargetFileName, int dwFlags);
        '
    Add-Type -MemberDefinition $signature -Name Creator -Namespace SymbolicLink

    $Flags = [Int]($Type -eq 'Directory')
    [SymbolicLink.Creator]::CreateSymbolicLink($MirroredPath, $OriginalPath,$Flags)
}

$downloads = "$env:userprofile\Downloads"
$desktop = "$env:userprofile\Desktop\MyDownloads"

New-SymbolicLink -OriginalPath $downloads -MirroredPath $desktop -Type Directory

当您(以管理员身份)运行这段代码时,它将使您能在桌面上访问下载文件夹。请右击符号链接并选择属性,并和“普通”的*.link文件做对比。

评论

PowerShell 技能连载 - 检查管理员权限

以下通过一个非常规的办法实现检查一段脚本是否以管理员权限运行(通过提升UAC),这体现了PowerShell强大的灵活性:

function Test-Admin { [bool]((whoami /groups) -match "S-1-16-12288") }

它的基本原理是检查当前用户是否是高完整性级别用户组的成员。该用户组是专门针对提升权限的管理员设置的。

如果您不想使用本地命令(whoami.exe)的话,还可以使用更贴近PowerShell(或.NET)的方法,如以下代码所示:

function Test-Admin {

    $id = New-Object Security.Principal.WindowsPrincipal $([Security.Principal.WindowsIdentity]::GetCurrent())

    $id.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)

}
评论