Подтвердить что ты не робот

Каковы некоторые из наиболее полезных, но малоизвестных функций на языке PowerShell

В то время как я читал о назначениях с несколькими переменными в PowerShell. Это позволяет вам делать что-то вроде этого

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

65 >  $a
A

66 >  $b
four

Или вы можете менять переменные в одном выражении

$a,$b = $b,$a

Какие малоизвестные самородки PowerShell вы сталкиваетесь с тем, что, по вашему мнению, не так хорошо известны, как должны быть?

4b9b3361

Ответ 1

Команда $$. Мне часто приходится выполнять повторные операции по одному и тому же пути к файлу. Например, проверьте файл, а затем откройте его в VIM. Функция $$ делает этот тривиальный

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

Это короткий и простой, но это экономит много времени.

Ответ 2

Самой мощной особенностью PowerShell является поддержка ScriptBlock. Тот факт, что вы можете так кратко передать то, что эффективно анонимные методы без каких-либо ограничений типа, столь же мощно, как и указатели на функции С++, и такие же простые, как С# или F # lambdas.

Я имею в виду, насколько здорово, что с помощью ScriptBlocks вы можете реализовать оператор "using" (который PowerShell не имеет по своей сути). Или, pre-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(...)
}

Как здорово это!

Ответ 3

Функция, которую я нахожу, часто упускается из виду - это возможность передать файл в оператор switch.

Переключатель будет перебирать строки и сопоставлять строки (или регулярные выражения с параметром -regex), содержимое переменных, чисел или строки может быть передано в выражение, которое будет оцениваться как $true или $false

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

Ответ 4

$OFS - разделитель полей вывода. Удобный способ указать, как элементы массива разделяются при визуализации в строку:

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

Всегда гарантируя, что вы получите результат массива. Рассмотрим этот код:

PS> $files = dir *.iMayNotExist
PS> $files.length

$файлы в этом случае могут быть $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

Сравнение массивов с использованием 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

Чтобы найти больше таких вещей, посмотрите мою бесплатную электронную книгу - Эффективный PowerShell.

Ответ 5

Вдоль строк назначений с несколькими переменными.

$list = 1,2,3,4

Пока ($ list) {
$ head, $list = $list
$ Голова
}

1
2
3
4

Ответ 6

Я использовал это:

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

и я также довольно часто использую $_ (текущий объект конвейера), но они могут быть более известны, чем другие.

Ответ 7

Тот факт, что многие операторы также работают с массивами и возвращают элементы, где сравнение истинно или работает на каждом элементе массива независимо:

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

Это быстрее, чем Where-Object.

Ответ 8

Не функция языка, но очень полезная

f8 - принимает текст, который вы уже ввели, и ищет команду, начинающуюся с этого текста.

Ответ 9

Вкладка - поиск по вашей истории с помощью #

Пример:

PS > Проводник Get-Process
PS > "Ford Explorer"
PS > "Магеллан" | Добавить контент "great explorers.txt"
PS > тип "great explorers.txt"
PS > #expl < - Хит <tab> ключ для циклического перехода через записи истории, которые имеют термин "expl"

Ответ 10

Люблю эту ветку. Я мог бы перечислить массу вещей после прочтения Windows Powershell в действии. Есть разрыв между этой книгой и документацией. Я на самом деле пытался перечислить их всех где-то еще здесь, но был отложен из-за "не вопрос".

Я начну с 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

get- content/Set-content с переменными:

$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 '& amp;', а затем ждать их:

$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:

[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.

Демонстрация рабочих процессов, переживающих прерывания с использованием контрольных точек. Убейте окно или перезагрузите компьютер. Затем снова запустите PS. Используйте get- job и resume-job, чтобы возобновить работу.

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

Режим редактирования Emacs. Нажатие на вкладку завершения перечисляет все опции одновременно. Очень полезно.

Set-PSReadLineOption -EditMode Emacs

Любую команду, которая начинается с "get-", вы можете опустить "get-":

date
help

Завершить анализ --% и завершить параметры операторов --.

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

Завершение табуляции в подстановочных знаках:

cd \pro*iles # press tab

Скомпилируйте и импортируйте модуль С# с командлетом внутри, даже в Osx:

Add-Type -Path ExampleModule.cs -OutputAssembly ExampleModule.dll
Import-Module ./ExampleModule.dll

Ответ 11

Выполните итерацию в обратном порядке по последовательности, просто используйте len последовательности с 1 на другой стороне диапазона:

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