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 技能连载 - 设置显示器亮度

如果您的显示驱动程序支持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)

}

PowerShell 技能连载 - 创建硬连接

硬连接是NTFS文件系统中文件的“镜像”。它们使得一个文件能在多个文件系统位置(必须在一个卷中)中出现。

所以文件仅仅占用它的原始位置空间,但是在其它地方也可用。当您需要让大文件在多个地方可用的时候,这是一个十分有用的功能。

以下是 New-HardLink 函数的介绍。它演示了PowerShell如何调用底层的API函数:

function New-HardLink
{
    param
    (
        [Parameter(Mandatory=$true)]
        $OriginalFilePath,

        [Parameter(Mandatory=$true)]
        $MirroredFilePath
    )

    $signature = '
            [DllImport("Kernel32.dll")]
            public static extern bool CreateHardLink(string lpFileName,string lpExistingFileName,IntPtr lpSecurityAttributes);
    '
    Add-Type -MemberDefinition $signature -Name Creator -Namespace Link

    [Link.Creator]::CreateHardLink($MirroredFilePath,$OriginalFilePath,[IntPtr]::Zero)

}

以下是它的使用方法:

$Original = "$env:temp\testfile.txt"
$Copy1 = "$env:userprofile\Desktop\mirrorfile1.txt"
$Copy2 = "$env:userprofile\Desktop\mirrorfile2.txt"

# create original file:
Set-Content -Path $Original -Value 'Hello'

# create hard link #1:
New-HardLink -OriginalFilePath $Original -MirroredFilePath $Copy1

# create hard link #2:
New-HardLink -OriginalFilePath $Original -MirroredFilePath $Copy2

这段代码首先在临时文件夹中创建一个物理文件。然后在您的桌面上创建两个硬连接。它们看上去分别是mirrorfile1.txtmirrorfile2.txt。虽然它们看上去像是独立的文件,而实际上他们都指向刚创建的临时文件。

您可以打开桌面上两个文件中的某一个,做一些修改,然后保存并关闭。当打开另一个文件时,您可以看到一模一样的修改后的内容。您还可以简单地删掉一个镜像文件来移除硬连接。

用 PowerShell 处理纯文本 - 1

原始文本:”data1”:111,”data2”:22,”data3”:3,”data4”:4444444,”data5”:589
要求:转换成对象

方法一,采用字符串运算及 ConvertFrom-StringData 命令:

$rawTxt='"data1":111,"data2":22,"data3":3,"data4":4444444'
$rawTxt -split ',' | ForEach-Object {
   $temp= $_ -split ':'
   "{0}={1}" -f $temp[0].Substring(1,$temp[0].Length-2),$temp[1]
} | ConvertFrom-StringData

方法二,采用正则表达式,使用.NET的方法:

$rawTxt = '"data1":111,"data2":22,"data3":3,"data4":4444444,"data5":589'
$regex = [regex] '"(?<name>\w*)":(?<value>\d*),?'
$match = $regex.Match($rawTxt)
while ($match.Success) {
	[PSCustomObject]@{
	    Name = $match.Groups['name'].Value
	    Value = $match.Groups['value'].Value
	}
	$match = $match.NextMatch()
}

方法三,采用正则表达式,使用 Select-String Cmdlet:

Select-String -InputObject $rawTxt -Pattern $regex -AllMatches | % {
    $_.Matches
} | % {
   [PSCustomObject]@{
        Name = $_.Groups['name'].Value
        Value = $_.Groups['value'].Value
    }
}

三者的执行结果都是这样:

Name          Value
----          -----
data1         111
data2         22
data3         3
data4         4444444
data5         589

原命题参见:[PowerShell 文本处理实例(三)] 1

获取2013年剩余天数

用PowerShell获取2013年剩余天数的两种写法。

((Get-Date 2014-1-1) - (Get-Date)).Days
100

([datetime]"2014-1-1" - [datetime]::now).Days
100

顺便励志一下,2013年只剩下100天了。Come on,小伙伴们!

在PowerShell中操作Excel - 读取数据

欢迎回到“在PowerShell中操作Excel”三部曲系列文章。在这一系列的前两部分,我们学习了如何将数据写入Excel并且创建“富”报表,以及额外的格式化选项等Microsoft Excel高级用法。

对于IT专家来说,这个故事的另一半是如何从一个Excel文档中读取数据。它的挑战性在于您必须事先知道工作表的结构。我们可以搜索数据,但那是更复杂的情况。我假设您已有一个用过且了其解结构的Excel文档。这样,用PowerShell读取数据就不那么复杂。

读取数据

像我们在本系列文章的前两部分那样,第一步是创建一个Excel应用程序对象。

$xl=New-Object -ComObject "Excel.Application"

我将在我的脚本中使用这个Excel文件。

Excel数据

用工作簿对象的 Open() 方法打开文件。

$wb=$xl.Workbooks.Open($file)
$ws=$wb.ActiveSheet

$ws对象是我们对数据最重要的的引用点。我需要用的数据从A2单元格开始。在我的测试环境中,我也许知道我需要处理多少行,但是既然我知道从哪儿开始,我可以用一个Do循环来读取每一行,获取数据,进行进一步操作。

$Row=2

do {
  $data=$ws.Range("A$Row").Text
...

通过使用Range属性,我可以获取A2单元格。Text属性是该单元格的值。我的示例脚本将要从第一列获取计算机名,获取一些WMI信息,然后向管道写入一个和电子表格的其它部分数据有关的自定义数据。

当您处理Excel数据的时候,我建议您进行一系列校验。假设单元格里有一个数据,我假设它是一个机器名,那么我会试着ping一下它。

if ($data) {
    Write-Verbose "Querying $data"
      $ping=Test-Connection -ComputerName $data -Quiet

如果ping通了,我将会使用WMI来获取操作系统名称,否则我会设置$OS变量为$Null。

if ($Ping) {
        $OS=(Get-WmiObject -Class Win32_OperatingSystem -Property Caption -computer $data).Caption
      }
      else {
        $OS=$Null

最后,对于每台计算机,我将用 New-Object cmdlet创建一个自定义对象。

New-Object -TypeName PSObject -Property @{
        Computername=$Data.ToUpper()
        OS=$OS
        Ping=$Ping
        Location=$ws.Range("B$Row").Text
        AssetAge=((Get-Date)-($ws.Range("D$Row").Text -as [datetime])).TotalDays -as [int]
      }

请注意我设置的其它属性值,比如说Location,是位于B2单元格,至少对于这台计算机而言。请注意您从它的Text属性获取到的只是文本。但您还可以将它们转换为各种数据类型,就像我对AssetAge属性的处理那样。我从D2单元格读取文本,并把它转换为一个 DateTime 对象,于是我可以将它和当前时间做减法,得到一个 TimeSpan 对象。该对象有一个 TotalDays 属性。

loop循环的最后一步是使行计数器自增1。

$Row++
} While ($data)

下一次进入lopp循环的时候,脚本将会处理第3行的数据。直到PowerShell遇到一个空行。在最后,我将关闭文件并且退出。

$xl.displayAlerts=$False
$wb.Close()
$xl.Application.Quit()

我的脚本运行以后生成一下输出结果:

PS C:\scripts> .\Demo-ReadExcel.ps1

AssetAge     : 687
Ping         : True
Computername : SERENITY
Location     : R1-1
OS           : Microsoft Windows 7 Ultimate

AssetAge     : 293
Ping         : True
Computername : QUARK
Location     : R1-4
OS           : Microsoft Windows 7 Professional

AssetAge     : 293
Ping         : False
Computername : SERVER01
Location     : R3-2
OS           :

AssetAge     : 2005
Ping         : True
Computername : JDHIT-DC01
Location     : R2-1
OS           : Microsoft(R) Windows(R) Server 2003, Enterprise Edition

我在PowerShell中用数的代码就可以实现从Excel电子表格中读取数据并且在我的程序中使用它。如果需要的话,我可以结合前面文章中的技术,在读取的同时更新电子表格的内容!

结论

您可以下载我的示例脚本并且自己做一下实验。记住,当使用PowerShell读取Excel文件的时候,您需要事先了解文档的结构,并且做好错误处理和数据有效性验证。我并不推荐初学者用PowerShell操作Excel,但具有一些经验并投入一些耐心以后,您可以得到很丰厚的回报。

用PowerShell操作Office系列文章

PowerShell 技能连载 - 在文件管理器中显示隐藏文件

PowerShell可以方便地读写注册表。注册表是Windows设置的中心仓库。

这是一个可以设置文件管理器显示/不显示隐藏文件的函数。它聪明的地方在于不需要向注册表写入新值。它相当于文件管理器窗口如何显示和改变它们的内容。

function Show-HiddenFile
{
    param([Switch]$Off)

    $value = -not $Off.IsPresent
    Set-ItemProperty -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced `
    -Name Hidden -Value $value -type DWORD

    $shell = New-Object -ComObject Shell.Application
    $shell.Windows() |
        Where-Object { $_.document.url -eq $null } |
        ForEach-Object { $_.Refresh() }
}

Show-HiddenFile 使得隐藏文件变得可见而 Show-HiddenFile -Off 使得隐藏文件不可见。操作结果几乎在所有文件管理窗口中立即生效。如果您在没有打开文件管理窗口的情况下做出改变,则改变不会立即生效,因为没有可以调用 Refresh() 方法的窗口。

PowerShell 技术 QQ 群