PowerShell语言中有哪些最有用但鲜为人知的功能

时间:2009-05-21 14:45:24

标签: powershell

前段时间我正在阅读有关PowerShell中多变量赋值的内容。这可以让你做这样的事情

64 >  $a,$b,$c,$d = "A four word string".split()

65 >  $a
A

66 >  $b
four

或者您可以在单个语句中交换变量

$a,$b = $b,$a

你认为PowerShell有哪些鲜为人知的小块,你认为它们可能并不像它们应该的那样众所周知?

11 个答案:

答案 0 :(得分:19)

到目前为止,PowerShell最强大的功能是ScriptBlock支持。事实上你可以如此简洁地传递什么是有效的匿名方法而没有任何类型约束,这与C ++函数指针一样强大,就像C#或F#lambdas一样简单。

我的意思是说使用ScriptBlocks你可以实现一个“使用”语句(PowerShell本身没有)是多么酷。或者,在v2之前,你甚至可以实现try-catch-finally

function Using([Object]$Resource,[ScriptBlock]$Script) {
    try {
        &$Script
    }
    finally {
        if ($Resource -is [IDisposable]) { $Resource.Dispose() }
    }
}

Using ($File = [IO.File]::CreateText("$PWD\blah.txt")) {
   $File.WriteLine(...)
}

那有多酷!

答案 1 :(得分:19)

$$命令。我经常需要在同一文件路径上重复操作。例如,签出一个文件,然后在VIM中打开它。 $$功能使这一点变得微不足道

PS> tf edit some\really\long\file\path.cpp
PS> gvim $$

它既简短又简单,但可节省大量时间。

答案 2 :(得分:15)

我发现的一个功能经常被忽略的是能够将文件传递给switch语句。

Switch将迭代这些行并匹配字符串(或带有-regex参数的正则表达式),变量,数字或行的内容可以传递给表达式,以便计算为$ true或$ false

switch -file 'C:\test.txt' 
{   
  'sometext' {Do-Something}   
  $pwd {Do-SomethingElse}  
  42 {Write-Host "That's the answer."}  
  {Test-Path $_} {Do-AThirdThing}  
  default {'Nothing else matched'} 
}

答案 3 :(得分:13)

$ OFS - output field separator。一种指定数组元素在呈现为字符串时如何分离的方便方法:

PS> $OFS = ', '
PS> "$(1..5)"
1, 2, 3, 4, 5
PS> $OFS = ';'
PS> "$(1..5)"
1;2;3;4;5
PS> $OFS = $null # set back to default
PS> "$(1..5)"
1 2 3 4 5

Always guaranteeing you get an array result。请考虑以下代码:

PS> $files = dir *.iMayNotExist
PS> $files.length
在这种情况下,$ p文件可能是$ null,标量值或值数组。 $ files.length不会为您提供$ null或单个文件的文件数。在单个文件的情况下,您将获得文件的大小!每当我不确定我将获得多少数据时,我总是将命令包含在数组子表达式中,如下所示:

PS> $files = @(dir *.iMayNotExist)
PS> $files.length # always returns number of files in array

然后$ files将始终是一个数组。它可能是空的,或者只有一个元素,但它是一个数组。这使得推理结果更加简单。

阵列协方差支持:

PS> $arr = '127.0.0.1','192.168.1.100','192.168.1.101'
PS> $ips = [system.net.ipaddress[]]$arr
PS> $ips | ft IPAddressToString, AddressFamily -auto

IPAddressToString AddressFamily
----------------- -------------
127.0.0.1          InterNetwork
192.168.1.100      InterNetwork
192.168.1.101      InterNetwork

Comparing arrays using Compare-Object

PS> $preamble = [System.Text.Encoding]::UTF8.GetPreamble()
PS> $preamble | foreach {"0x{0:X2}" -f $_}
0xEF
0xBB
0xBF
PS> $fileHeader = Get-Content Utf8File.txt -Enc byte -Total 3
PS> $fileheader | foreach {"0x{0:X2}" -f $_}
0xEF
0xBB
0xBF
PS> @(Compare-Object $preamble $fileHeader -sync 0).Length -eq 0
True

更多这样的东西,看看我的免费电子书 - Effective PowerShell

答案 4 :(得分:10)

沿着多变量分配的路线。

$ list = 1,2,3,4

while($ list){
  $ head,$ list = $ list
  $头
}

1
2
3
4

答案 5 :(得分:8)

我一直在用这个:

if (!$?) {  # if previous command was not successful
    Do some stuff
}

我也使用$ _(当前管道对象),但这些可能比其他东西更为人所知。

答案 6 :(得分:6)

许多运算符也在数组上工作并返回比较为真的元素或者独立地对数组的每个元素进行操作这一事实:

1..1000 -lt 800 -gt 400 -like "?[5-9]0" -replace 0 -as "int[]" -as "char[]" -notmatch "\d"

这比Where-Object快。

答案 7 :(得分:3)

使用#

在标签中搜索您的历史记录

示例:

PS> Get-Process资源管理器
PS> “福特探索者”
PS> “麦哲伦”|添加内容“伟大的explorers.txt”
PS>输入“great explorers.txt”
PS> #expl < - 点击< tab>循环浏览具有术语“expl”

的历史记录条目的关键

答案 8 :(得分:3)

不是语言功能,但非常有用

f8 - 获取已放入的文本并搜索以该文本开头的命令。

答案 9 :(得分:1)

在序列上向后迭代只需使用序列的len,并在该范围的另一端使用1。

foreach(x in seq.length..1){Do-Something seq [x]}

答案 10 :(得分:1)

喜欢这个主题。在阅读《 Windows Powershell in Action》后,我可能会列出很多东西。那本书和文档之间是脱节的。我实际上试图将它们都列出来,但由于“不是问题”而被搁置。

我将从三个脚本块(开始/过程/结束)的foreach开始:

Get-ChildItem | ForEach-Object {$sum=0} {$sum++} {$sum}

谈到交换两个变量,这里是交换两个文件:

${c:file1.txt},${c:file2.txt} = ${c:file2.txt},${c:file1.txt}

搜索并替换文件:

${c:file.txt} = ${c:file.txt} -replace 'oldstring','newstring'

使用程序集并使用名称空间语句:

using assembly System.Windows.Forms
using namespace System.Windows.Forms
[messagebox]::show('hello world')

foreach的较短版本,具有属性和方法

ps | foreach name
'hi.there' | Foreach Split .

在字符串之外使用$()运算符组合两个语句:

$( echo hi; echo there ) | measure

使用变量获取内容/设置内容

$a = ''
get-content variable:a | set-content -value there

匿名功能:

1..5 | & {process{$_ * 2}}

为匿名函数命名:

$function:timestwo = {process{$_ * 2}}

带有参数的匿名函数:

& {param($x,$y) $x+$y} 2 5

您可以使用以下方法从foreach()中进行流式传输,而通常情况下,您不能:

& { foreach ($i in 1..10) {$i; sleep 1} } | out-gridview

在后台运行unix'&'之类的进程,然后等待它们:

$a = start-process -NoNewWindow powershell {timeout 10; 'done a'} -PassThru
$b = start-process -NoNewWindow powershell {timeout 10; 'done b'} -PassThru
$c = start-process -NoNewWindow powershell {timeout 10; 'done c'} -PassThru
$a,$b,$c | wait-process

或者在工作流程中使用foreach -parallel:

workflow work {
  foreach -parallel ($i in 1..3) { 
    sleep 5 
    "$i done" 
  }
}

work

或工作流并行块,您可以在其中运行不同的事情:

function sleepfor($time) { sleep $time; "sleepfor $time done"}

workflow work {
  parallel {
    sleepfor 3
    sleepfor 2
    sleepfor 1
  }
  'hi'
}

work 

使用api在另外三个运行空间中的三个并行命令:

$a =  [PowerShell]::Create().AddScript{sleep 5;'a done'}
$b =  [PowerShell]::Create().AddScript{sleep 5;'b done'}
$c =  [PowerShell]::Create().AddScript{sleep 5;'c done'}
$r1,$r2,$r3 = ($a,$b,$c).begininvoke()

$a.EndInvoke($r1); $b.EndInvoke($r2); $c.EndInvoke($r3) # wait
($a,$b,$c).Streams.Error # check for errors
($a,$b,$c).dispose() # cleanup

使用invoke-command进行并行处理,但是您必须在远程Powershell运行的情况下处于提升状态:

invoke-command localhost,localhost,localhost { sleep 5; 'hi' } 

分配是一个表达式:

if ($a = 1) { $a } 
$a = $b = 2

使用-1获取最后一个数组元素:

(1,2,3)[-1]

使用[void]放弃输出:

[void] (echo discard me)

打开数组,并在任一侧打开$ _

switch(1,2,3,4,5,6) {
  {$_ % 2} {"Odd $_"; continue}
  4 {'FOUR'}
  default {"Even $_"}
}

在模块中获取并设置变量

'$script:count = 0
$script:increment = 1
function Get-Count { return $script:count += $increment }' > counter.psm1 # creating file

import-module .\counter.psm1

$m = get-module counter
& $m Get-Variable count
& $m Set-Variable count 33

请参阅模块功能定义:

& $m Get-Item function:Get-Count | foreach definition

使用commandinfo对象和调用运算符运行命令:

$d = get-command get-date
& $d

动态模块:

$m = New-Module {
  function foo {"In foo x is $x"}
  $x=2
  Export-ModuleMember -func foo -var x
}

标志枚举:

[flags()] enum bits {one = 1; two = 2; three = 4; four = 8; five = 16}
[bits]31

-replace运算符鲜为人知的代码:

$number Substitutes the last submatch matched by group number.
${name} Substitutes the last submatch matched by a named capture of the form (?).
$$ Substitutes a single "$" literal.
$& Substitutes a copy of the entire match itself.
$` Substitutes all the text from the argument string before the matching portion.
$' Substitutes all the text of the argument string after the matching portion.
$+ Substitutes the last submatch captured.
$_ Substitutes the entire argument string.

使用检查点在中断中幸存的工作流示例:

workflow test1 {
  foreach ($b in 1..1000) {
    $b
    Checkpoint-Workflow
  }
}
test1 -AsJob -JobName bootjob

杀死窗口或重新启动。然后再次启动PS。使用get-job和resume-job来恢复工作。

Emacs编辑模式。按制表符补全一次列出所有选项。非常有用。

Set-PSReadLineOption -EditMode Emacs

任何以“ get-”开头的命令,都可以省略“ get-”,例如date而不是get-date

结束解析--%和结束参数--运算符。

write-output --% -inputobject
write-output -- -inputobject