Powershell

查看powershell版本

1
2
3
get-host
$Host
$PSVersionTable

查看命令的alias
get-alias ls

获取帮助
get-help

一行多条命令用;连接
cd c:\users ; dir

提前结束脚本
用exit, 而不是Exit

boolean常量

1
2
$true # true
$false # false

数据类型
[int]
Integer numbers
[single] and [double]
Single-precision and double-precision floating numbers (numbers with a decimal portion)
[string]
A string of characters
[char]
Exactly one character (as in, [char]$c = 'X')
[xml]
An XML document
whatever string you assign to this will be parsed to make sure it contains valid XML markup
(for example, [xml]$doc = Get-Content MyXML.xml)

变量解析规则
$不是变量的一部分
If the character immediately after the dollar sign is a letter, number, or underscore,
the variable name consists of all the characters following the dollar sign,
up to the next white space (which might be a space, tab, or carriage return).
If the character immediately after the dollar sign is an opening curly brace, {,
the variable name consists of everything after that curly brace up to,
but not including, the closing curly brace, }.

One script, one pipeline
This different output occurs because the script writes two kinds of objects to a singlepipeline.
This is the important difference between putting commands into a scriptand running them manually:
Within a script, you have only one pipeline to work with.
Normally, your scripts should strive to output only one kind of object,
so that Power-Shell can produce sensible text output.

作用域
A scope lasts only as long as needed to execute whatever is in the scope.
The globalscope exists only while PowerShell is running,
a script scope exists only while that scriptis running, and so forth.
When whatever it is stops running, the scope vanishes, takingeverything inside it with it.
PowerShell has specific—and sometimes confusing—rulesfor scoped elements such as aliases, variables, and functions,
but the main rule is this:If you try to access a scoped element,
PowerShell sees whether it exists within the currentscope.
If it doesn’t, PowerShell sees whether it exists in the current scope’s parent.
It continues going up the relationship tree until it gets to the global scope.

在不同目录中切换

1
2
Push-Location -StackName ps
Pop-Location -StackName ps

帮助文件中的标点符号
Punctuation within the help file takes on slightly different meanings:
[ ] Square brackets that surround any text indicate that the text is optional.
That might include an entire command ([-Name <string>]),
or it might indicate that a parameter is positional and that the name is optional ([-Name] <string>).
It can also indicate both that a parameter is optional and,
if used, can be used positionally ([[-Name] <string>]).
It’s always legal to use the parameter name, if you’re in any doubt.
[ ] Adjacent square brackets indicate that a parameter can accept multiple values (<string[]> instead of <string>).
< > Angle brackets surround data types, indicating what kind of value or object
a parameter expects: <string>, <int>, <process>, and so forth.

判断操作系统位数

1
2
[Environment]::Is64BitOperatingSystem
(Get-WmiObject Win32_OperatingSystem).osarchitecture

判断Windows操作系统版本

1
[Environment]::OSVersion.VersionString -like "*10.*"

powershell判断操作系统版本命令

提前退出脚本
exit

当前脚本执行目录
$PSScript123456

获取当前执行脚本的完整路径名

1
2
$MyInvocation.MyCommand.Path
$PSCommandPath

获取当前执行脚本的名称

1
$MyInvocation.MyCommand.Name

获取当前执行脚本的内容

1
$MyInvocation.MyCommand.ScriptContents

函数模版
BEGIN和END代码块只会被执行一次

1
2
3
4
5
6
7
function <name> {
[CmdletBinding()]
param()
BEGIN {}
PROCESS {}
END {}
}

Trace the actions of ParameterBinding operations

1
2
$A = "i*"
Trace-Command ParameterBinding {Get-Alias $Input} -PSHost -InputObject $A

查看命令的实现/源码

1
(Get-Command Unlock-BitLocker).Definition

设置互斥参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function Test-ParameterSet
{
[CmdletBinding(DefaultParameterSetName='number')]
param
(
[int]
[Parameter(ParameterSetName='number', Position=0)]
$id,
[string]
[Parameter(ParameterSetName='text', Position=0)]
$name
)
$PSCmdlet.ParameterSetName
$PSBoundParameters
}
# -id和-name参数,只能二选一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Test-ParameterSet {
[CmdletBinding(DefaultParameterSetName = 'backup')]
param
(
[Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)]
[ValidateSet('backup', 'restore')]
[String]$operation,
[Parameter(ValueFromPipeline = $true, Position = 1)]
[ValidateSet('all', 'part')]
[String]$optparam = 'all'
)
$PSCmdlet.ParameterSetName
$PSBoundParameters
'$optparam = '+$optparam
}

数组求并集,交集,差集

1
2
3
$a + $b | select -uniq # union
$a | where {$b -contains $_} # intersection
$a | where {$b -notcontains $_} # subtraction

环境变量
输入$, 按Tab可显示全部环境变量

1
2
3
4
5
6
$env:APPDATA
# $home\AppData\Roaming
$env:LOCALAPPDATA
# $home\AppData\Local
$env:programfiles
# 一般是C:\Program Files

providers
A PowerShell provider, or PSProvider, is an adapter.
It’s designed to take some kind of data storage and make it look like a disk drive.

1
2
Get-PSProvider
cd env:

软件包管理

1
2
3
4
Find-Module
Find-Script
Install-Module
Uninstall-Module

用get-member获得对象的成员信息

1
get-process | get-member

脚本块

1
2
$block = {get-process | sort -Property vm -Descending | select -first 10 }
&$block

[cmdletbinding()]
Using the cmdletbinding attribute to simplify Windows PowerShell functions.

杀死进程

1
Get-Process TIM | Stop-Process

隐藏文件

1
2
$f=get-item $home\pip -Force
$f.attributes="Hidden"

引号转义

1
2
$a=123
" abc ""$a"" abc"

1
2
$db='tp5'
$dbCopy = '`' + $db + '`'
1
2
3
4
$sql = @"
DROP DATABASE IF EXISTS ``$dbCopy``;
"@
$sql

Dynamically generate command-line command, then invoke using powershell
Creating your own ScriptBlock

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Create your own scriptblock without argument
$NewScriptBlock = [scriptblock]::Create("Get-ChildItem")
# Executing the scriptblock
$NewScriptBlock.Invoke()
# It also can be reused, example with Invoke-Command
Invoke-Command -ScriptBlock $NewScriptBlock
# Pass one parameter
$MyPath = 'c:\windows'
$NewScriptBlock = [scriptblock]::Create("Get-Childitem -path $MyPath")
# Execute the scriptblock
$NewScriptBlock.Invoke()
# Pass multiple parameters
$MyPath = 'c:\windows'
$MyFilter = '*.log'
$NewScriptBlock = [scriptblock]::Create("Get-Childitem -path $MyPath -filter $MyFilter")
# Execute the scriptblock
$NewScriptBlock.Invoke()
# Or Using it with invoke-command
Invoke-Command -ScriptBlock $NewScriptBlock
# Works as well against one or multiple machines
Invoke-Command -ScriptBlock $NewScriptBlock -ComputerName MyServer

Create and reuse a powershell scriptblock
dynamically-generate-command-line-command-then-invoke-using-powershell

时间格式化

1
Get-Date -UFormat "%Y-%m-%d %H:%M:%S"

命令行输出,对象转换成文本
Powershell已经内置Out-Default命令追加在管道的命令串的末尾.
因此你使用dir 和dir | out-default的结果是相同的.
Out-Default可以将对象转换成可视的文本.
事实上Out-Default会首先调用Format-Table, 将更多的属性默认隐藏.
再调用Out-Host将结果输出在控制台上。因此下面的三组命令执行结果是相同的.

1
2
3
ls
ls | Format-Table | Out-Host
ls | Out-Default

要查看对象结果的所有属性,使用

1
ls | Format-Table *

这样因为属性和属性的内容太多可能不会显示完全,可以使用文本换行参数

1
ls | Format-Table * -Wrap

用PSCustomObject创建对象

1
(0..5) | ForEach-Object {[PSCustomObject]@{Name = "Test Name"; ID = $_}}

Get-Content的Raw参数
Read file as a string-object-with-CRLFs. As opposed to an array of strings split on CRLF.

1
(Get-Content $path -Encoding UTF8) | Out-File $path -Encoding UTF8 -nonewline

删除空目录

1
2
3
Get-ChildItem -Path $dir -recurse | Where-Object { $_.PSIsContainer -and `
@(Get-ChildItem -LiteralPath $_.Fullname -Recurse | Where-Object {!$_.PSIsContainer}).Length -eq 0 } |
Remove-Item -recurse -Confirm

删除旧文件

1
2
Get-ChildItem -recurse | Where-Object { !$_.PSIsContainer -and `
$_.LastWriteTime -lt (get-date).AddDays(-31) } | Remove-Item -Confirm

列出文件让用户选择

1
2
$fileList = Get-ChildItem -Path "$home\Documents\books" -File -Include $name -Recurse
$selectedFile = @( $fileList | Out-GridView -Title 'Choose a file' -PassThru)

Powershell to list files and have the user select one

只有当该进程结束才会执行下一条命令

1
2
Start-Process "notepad" -ArgumentList "1.txt" -wait
get-content "1.txt"

Out-String
The Out-String cmdlet converts the objects that Windows PowerShell manages into an array of strings.
By default, Out-String accumulates the strings and returns them as a single string,
but you can use the stream parameter to direct Out-String to return one string at a time.
This cmdlet lets you search and manipulate string output as you would in traditional shells
when object manipulation is less convenient.
-Stream
Indicates that the cmdlet sends the strings for each object separately.
By default, the strings for each object are accumulated and sent as a single string.

删除utf8 bom
using-powershell-to-write-a-file-in-utf-8-without-the-bom
Out-FileUtf8NoBom.psm1

判断字符串是空或未定义

1
[string]::IsNullOrEmpty()

判断变量的类型

1
2
$str="abc"
$str -is [String]

替换换行符的4种写法

1
2
3
4
5
6
(Get-Content $path -Raw -Encoding UTF8) -replace "`r", "" | Out-File $path -Encoding UTF8 -nonewline
[regex]::Replace((Get-Content $path -Raw -Encoding UTF8), "`r", "") | Out-File $path -Encoding UTF8 -nonewline
(Get-Content $path -Encoding UTF8 | Out-String) -replace "`r", "" | Out-File $path -Encoding UTF8 -nonewline
$text=(Get-Content $path -Raw -Encoding UTF8) -replace "`r", ""
[io.file]::WriteAllText(($path, $text)
# "`r" 也可以是 "\r" 或 '\r', 但不能是'`r'

用param()定义参数
Use param() Blocks

删除注释

1
2
3
$content = Get-Content $path | Where-Object {
-not ([String]::IsNullOrEmpty($_.Trim()) -or $_ -match "^\s*// ")
} | ForEach-Object { $_ -replace "(.*)(// .*)", '$1' }

how-to-remove-comments-from-text-file

Regex Replacing with captures

1
$str = [regex]::Replace($str, "<i>(\w+)</i>", '$1 $1');

Notice the single quotes around the replacement pattern.
This is to keep PowerShell from interpreting "$1" before passing passing it to the Regex class.
We could use double quotes if we also put back ticks in front of the dollar signs to escape them.

case-insensitive and case-sensitive method
The -iSplit and -split operators are case-insensitive.
The -cSplit operator is case-sensitive, meaning that case is considered when the delimiter rules are applied.
Replace()是大小写敏感的,-replace操作符是大小写不敏感的

正则表达式转义

1
2
[Regex]::Escape('.')
"`n" #回车

对于使用-replace进行"查找"和"替换", 只需要对"查找"转义.

1
2
3
$oldStr2 = [Regex]::Escape("multi_line = False")
$newStr2 = "multi_line = True"
$sth -replace $oldStr2, $newStr2

匹配带$的字符串

1
2
3
$str="`$pathValues='';"
$str
$str -match "\`$pathValues='.*';"

[regex]::Match()和[regex]::Matches()

1
2
3
$str = 'a1b2c3d4567e'
$firstMatch = [regex]::Match($str,'\d+')
$allMatch = [regex]::Matches($str,'\d+')

对象的foreach()方法

1
2
3
$str = 'a1b2c3d4567e'
$allMatch = [regex]::Matches($str,'\d+')
$allMatch.foreach('value')

逆向匹配

1
2
3
# 得到HTMLPrettify2
$MatchOut=[regex]::Match("git@xp.com:victorporof/abc123/HTMLPrettify2.git","/(.+?)\.git","RightToLeft")
$MatchOut.Groups[1]

Regular expressions in PowerShell and Perl
正则表达式选项.aspx)
另一种方法

1
2
$str=split-path -leaf "git@xp.com:victorporof/abc123/HTMLPrettify2.git"
$str.Substring(0,$str.LastIndexOf(".git"))

_replace和$var.replace()
-replace 解析正则会转义,不区分大小写
powershell won't do $Var replacement on single quote strings,
but you need to escape again for the regex engine.
$var.replace() 不解析正则不转义,区分大小写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$var='---'
$content="$var[AutoProxy 0.2.9]"
$content = $content -replace '$var', ''
$content
# output
# ---[AutoProxy 0.2.9]
$content="$var[AutoProxy 0.2.9]"
$content = $content -replace '[AutoProxy 0.2.9]', ''
$content
# output
# ---[]
$content="$var[AutoProxy 0.2.9]"
$content = $content -replace '\[AutoProxy 0.2.9\]', ''
$content
# output
# ---

正则表达式多行模式
通常,多行模式是关闭的,此时限定符"^"代表文本的开始,"$"代表文本的结束.
要让这两个限定符可以代表文本行的开始和文本行的结束,必须使用"(?m)"来开启"多行"模式.
只有这样,–replace 才会在每个单独的文本行之间替换模式.
在"多行"模式开启后,限定符"^" 和 "\A", 还有"$" and "\Z"会顿时拥有不同的表现.
"\A"仍然会标志文本的开始,而"^"则会标志文本行的开始.
"\Z"仍然会标志文本的结尾,而"$"则会标志文本行结尾.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$text=@"
Line 1
! Line 2
Line 3
"@
Write-Output ($text -replace "^\!.+",'---')
# no change happen
# Line 1
# ! Line 2
# Line 3
Write-Output ($text -replace "(?m)^\!.+",'---')
# changed
# Line 1
# ---
# Line 3

在文本行的开始插入字符

运算符
进行比较
-eq : 等于
-ne : 不等于
-gt : 大于
-ge : 大于等于
-lt : 小于
-le : 小于等于
-contains : 包含 # 大小写不敏感
-ccontains: 包含 # 大小写敏感
-notcontains :不包含
布尔运算
-not : 求反
-and : 和
-or : 或
-xor : 异或
-not : 逆

正则表达式单行模式
Turn on "dot matches newline" for the remainder of the regular expression.

1
2
$DisplayNone = [regex]"(?s)";
$Content = (Get-Content $CopyPath -Raw -Encoding UTF8) -replace $DisplayNone, ''

作用域
$global
全局变量,在所有的作用域中有效,如果你在脚本或者函数中设置了全局变量,即使脚本和函数都运行结束,这个变量也任然有效.
$script
脚本变量,只会在脚本内部有效,包括脚本中的函数,一旦脚本运行结束,这个变量就会被回收.
写递归函数的时候,注意要用$script
$private
私有变量,只会在当前作用域有效,不能贯穿到其他作用域.
$local
默认变量,可以省略修饰符,在当前作用域有效,其它作用域只对它有只读权限.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function func () {
$var=4
# can't change the value of the outside $var
}
$var=3
func
echo $var
###############################################################
function func2 () {
echo $var
# can read outside $var
}
func2
################################################################
function func3 () {
$Script:var=4
}
$var=3
func3
echo $var

函数能够读取外部变量,但是不能修改外部变量

1
2
3
4
5
6
7
8
9
10
$arr = 1, 2, 3
function test () {
Write-Output $arr
$arr = + 4
}
test
Write-Output $arr

判断字符串是否包含某字符

1
2
3
$str="matter"
[string]$str.contains("m")
([regex]::match($str,"m")).success

contains()方法和-contains
字符串和数组都有contains()方法
-contains只用于数组

1
2
3
$str="matter*"
[string]$str.contains("r*")
$str -contains "r*"

host application
Windows PowerShell is actually an untouchable, behind-the-scenes engine.
We cannot easily interact directly with PowerShell.
We need a host application.
A host embeds the engine internally, and then gives us a way to interact with it.

Accumulating Output in a Function
PowerShell commands should usually output each object to the pipeline,
one at a time, as those objects are ready.
That allows the pipeline to accumulate the output,
and to immediately pass it along to whatever is next in the pipeline.
That's how PowerShell commands are intended to work.
Now, there are always exceptions.
Sort-Object, for example, has to accumulate its output,
because it can't actually sort anything until it has all of them.
So it's called a _blocking command,
because it "blocks" the pipeline from doing anything else until it produces its output.
But that's an exception.

数组去除重复元素

1
1,2,3,4,5,6,1,2,3,3,4,5,5 | Sort-Object -Unique

-in -contains 和-like的区别
The -in and -contains operators are best with simple values,
or with objects that don't have constantly-changing property values.
But they're not wild card string matching operators.
Use -like (or -notlike) for that.

out-file和set-content的区别
powershell-set-content-and-out-file-what-is-the-difference

PowerShell, being an interpreter, just goes through a script linearly top to bottom
why-do-i-need-to-have-my-functions-written-first-in-my-powershell-script

+号用法的区别
如果声明了$var=@()
$var=$var +$i会被当作往$var数组里面添加元素$i
如果没有这样声明,这样的操作会被认为是字符串连接或加法运算

定义数组和哈希表

1
2
3
4
5
6
$arr=1,2,3,4
###
$arr=@()
$arr[0]=1
###
$states = @{"Washington" = "Olympia"; "Oregon" = "Salem"; California = "Sacramento"}

遍历哈希表

1
2
3
4
5
6
7
8
9
10
11
$hash = @{
a = 1
b = 2
c = 3
}
foreach ($h in $hash.GetEnumerator()) {
Write-Host "$($h.Name): $($h.Value)"
}
foreach ($h in $hash.Keys) {
Write-Host "${h}: $($hash.Item($h))"
}

[PSCustomObject]转为hashtable
把hashtable转为json, 再转回来的对象不是hashtable类型,而是[PSCustomObject]

1
2
3
4
5
6
7
# Create a PSCustomObject (ironically using a hashtable)
$ht1 = @{ A = 'a'; B = 'b';}
$theObject = new-object psobject -Property $ht1
# Convert the PSCustomObject back to a hashtable
$ht2 = @{}
$theObject.psobject.properties | Foreach { $ht2[$_.Name] = $_.Value }

powershell - PSCustomObject to Hashtable

Write-Output和Write-Host
In a nutshell, Write-Host writes to the console itself. Think of it as a MsgBox in VBScript.
Write-Output, on the other hand, writes to the pipeline, so the next command can accept it as its input.
You are not required to use Write-Output in order to write objects,
as Write-Output is implicitly called for you.
powershell-difference-between-write-host-and-write-output
write-host类似于println, 自带换行

直接用$var和write-host $var的区别
write-host, 内容流入host, 不再流向管道

1
2
3
4
$var | export-csv filename.csv
# there will be the contents of $var inside the csv
write-host $var | export-csv filename.csv
# will not output to the csv

转换字符串到文件对象

1
2
$str="c:\"
get-item $str

删除重复行

1
2
3
Select-Object -Unique
# 使用.NET中的泛型类HashSet
[System.Collections.Generic.HashSet[string]]

PowerShell文本文件去除重复行

统计目录大小

1
(Get-ChildItem -Recurse | Measure-Object -Sum Length).Sum/1GB

查找0字节的jpg文件

1
Get-ChildItem -Path . -Recurse -Filter *.jpg | Where {$_.Length -eq 0} | Select-Object FullName |Format-Wide -Column 1

删除0字节的jpg文件

1
Get-ChildItem -Path . -Recurse -Filter *.jpg | Where {$_.Length -eq 0} | remove-Item

创建目录联接

1
New-Item -ItemType Junction -Path .\path\new-dir -Value .\path\test-dir

example.ps1

批量重命名

1
2
3
Get-ChildItem -name | Rename-Item -NewName { $_+".txt" }
Get-ChildItem | Rename-Item -NewName { $_.name+".txt" }
Get-ChildItem | Rename-Item -NewName { $_ -Replace '_', '-' }

1
2
3
4
5
6
7
8
9
10
11
12
13
function batch-rename($dir) {
$items = Get-ChildItem $dir
foreach ($i in $items) {
if ($i.PSIsContainer) {
batch-rename($i.pspath)
}
elseif($i.Name.EndsWith(".jpg") -or $i.Name.EndsWith(".png") -or $i.Name.EndsWith(".jpeg")) {
$i | Rename-Item -NewName { $i.Name -Replace '.+-', '' }
}
}
}
batch-rename .

转换单词为首字母大写

1
(Get-Culture).TextInfo.ToTitleCase()

转换目录文件名为首字母大写

1
2
3
4
5
6
7
8
$TextInfo = (Get-Culture).TextInfo;
Get-childitem -Directory | ForEach {
$NewName = $TextInfo.ToTitleCase($_);
If($_ -ne $NewName) {
cmd.exe /c rename $_ $NewName;
#mv $_ $NewName;
}
}

判断是否是目录

1
2
3
4
$var.PSIsContainer
###
Test-Path $_ -pathType container
Test-Path $_ -pathType leaf

判断文件是否存在
Check if a file exists or not
Verifying the Existence of a File or Folder

1
Test-Path $path

$json | convertto-json和convertto-json $json
when you pipe the variable to ConvertTo-Json it gets the individual elements of the array one at a time
When you pass it directly it's converting the array object
Just always pipe to the command

1
2
3
4
5
6
$uri = "https://rawgit.com/victorporof/Sublime-HTMLPrettify/master/Default%20(Windows).sublime-keymap"
$keymap = (Invoke-webrequest -URI $uri -Proxy "http://127.0.0.1:1080").content
$content= ConvertFrom-Json $keymap
$content | convertto-json
convertto-json $content

the automatic character escape feature of Convertto-Json
it affects several symbols such as <>\'&

replace-slash

1
2
filter replace-slash {$_ -replace "\\", "/"}
$homePath = $home | replace-slash

$input和$args

1
2
3
4
5
6
function test () {
$args
$input
}
test "aaa"
"bbb" | test

get url content

1
2
$uri="https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt"
$gfwlist=(Invoke-webrequest -URI $uri -Proxy "http://127.0.0.1:1080").Content

Convert-Path
Converts a path from a Windows PowerShell path to a Windows PowerShell provider path.
Convert-Path

循环
powershell-looping-understanding-and-using-do-whil

批量将文本转换成音频
convert-text-to-audio-file

进制转换
powershell本身支持十六进制,用0x开头表示.

1
2
3
4
# 十进制转二进制
[Convert]::ToString(192, 2)
# 二进制转十进制
[Convert]::ToInt32('11000000', 2)

数学运算

1
2
# 乘方
[math]::pow(2, 3)

子表达式
$() declares a sub-expression, it ensures the property is expanded before anything else takes over,
otherwise Write-Output treats everything as a string.
理解成没有变量名的变量,匿名变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$path= Resolve-Path "./test.json"
$json=ConvertFrom-Json(Get-Content($path) | Out-String)
$folder="**"+$json.name+"**"
write-Output $folder # Desired result 下面三个都不是我要的结果.
write-Output "**"+$json.name+"**"
write-Output "**"+($json.name)+"**"
# 修改成 write-Output ("**"+$json.name+"**")
write-Output "**"($json.name)"**"
"**$($json.name)**" # 还可以这样写,子表达式
# output
# **reddit**
# ** +@{name=reddit; url=https://www.reddit.com/}.name+**
# ** + reddit +**
# ** reddit **
# **reddit**

1
2
3
4
{
"name": "reddit",
"url": "https://www.reddit.com/"
}
1
2
3
4
5
6
7
8
class Link{
$name="badiu"
$url="www.baidu.com"
}
$item=[Link]::new()
echo "* [$($item.name)]`($($item.url)`)"
# * [baidu](www.baidu.com)

调用函数

1
2
3
4
5
6
function traverseBookmarks($bookmarks, $depth){
#do something
}
traverseBookmarks($bookmarks, 0) # 错误!
traverseBookmarks $bookmarks 0 # 正确的调用方式
traverseBookmarks $item.children ($depth + 2) # 第二个参数是表达式,要加上括号

调用函数传递多个参数

1
2
3
4
5
6
7
function run ([string[]]$name) {
foreach ($i in $name) {
Write-Output $i
}
}
run qq, idea

1
2
3
4
5
6
7
function run () {
foreach ($i in $args) {
Write-Output $i
}
}
run qq idea

string multiplication

1
2
3
"a" * 8
# output:
# aaaaaaaa

1
2
3
4
$space=' '
$folder='doc'
"$space* $folder`n" # *被解析为运算符,$space不需要用子表达式括起来
# 类似的符号还有+,-,/,%,\

Skipping the first from array

1
2
3
4
$arr=1,2,3,4
$arr[1..($arr.length-1)]
###
$arr | Select-Object -Skip 1

decode base64 string

1
[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String("YmxhaGJsYWg="))

how-to-decode-a-base64-string

由于对象不同造成的困扰

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$a = Get-ChildItem -Path "$home\Documents\books" -File -Recurse |
Where-Object {
$_.name -like "*powershell*"
}
$b = Get-ChildItem -Path "$home\Documents\books" -File -Recurse -include "*powershell*"
$a -eq $b
### false
### 因为$a和$b是不同的对象
$a.tostring()
### my-powershell-book.pdf
$b.tostring()
### c:\users\jin7\Doucments\books\my-powershell-book.pdf
### 注意,两者toString()的结果也不同

查看内置cmdlet源码
查看显示器信息

1
2
get-wmiobject -Query 'select * from Win32_PnPEntity where service="monitor"'
Get-CimInstance win32_desktopmonitor | Format-List *

在终端输入和输出UTF8编码字符

1
2
3
4
[Console]::InputEncoding = [System.Text.Encoding]::UTF8
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
Write-Host "Héllo!"
[Console]::WriteLine("Héllo")

修改代码页

1
2
3
chcp 437 #ASCII
chcp 936 #GBK
chcp 65001 #UTF-8

控制函数使用Begin、Process和End关键字处理来自管道的输入的方式
Begin语句列表只在函数的开头运行一次.
Process语句列表为管道中的每个对象运行一次。Process块在运行时,每个管道对象都被分配给 $_ 自动变量,一次分配一个管道对象.
在函数接收管道中的所有对象之后,End语句列表运行一次。如果不使用Begin、Process或End关键字,则所有语句将被视为End语句列表.

1
2
3
4
5
6
7
function Get-Pipeline{
process {"The value is: $_"}
}
1,2,4 | Get-Pipeline
# The value is: 1
# The value is: 2
# The value is: 4

ValueFromPipeline和ValueFromPipelineByPropertyName
ValueFromPipelin: 如果参数值没有在命令行中指定的话,它可以和管道输入的对象绑定在一起.
ValueFromPipelineByPropertyName: 如果参数值没有在命令行中指定的话,它可以和管道输入对象的属性绑定在一起.

动态创建变量

1
2
3
4
5
6
$name = "foo"
$value = "bar"
New-Variable -Name $name -Value $value
echo $foo
Get-Variable -Name "$name" -ValueOnly

使用hashtable

1
2
3
4
5
6
$vars = @{} # create empty dictionary
# add key/value pairs to dictionary:
$vars["foo"] = 23
$vars["bar"] = "foobar"
$vars["baz"] = Get-Content C:\sample.txt

Dynamic variable and value assignment in powershell

判断变量是否存在

1
2
3
4
5
if (Get-Variable foo -Scope Global -ErrorAction SilentlyContinue) {
$true
} else {
$false
}

字符串SubString()方法
Substring takes an index and a length parameter.

1
2
3
$str="abc123"
$str.SubString(0,2)
#"ab"

隐藏文件

1
2
$f=get-item my_file
$f.attributes="Hidden"

单引号转义
'Escape a single quote '' using a double single quote'

foreach-object完成文本替换

1
2
3
4
5
6
7
8
9
$content = Get-Content input.txt -Encoding UTF8
$content | ForEach-Object {
if ($_ -match '`<.+>`' ) {
$_ = $_ -replace '`<|<', '&lt;'
$_ -replace '>`|>', '&gt;'
}else{
$_
}
} | Out-File output.txt -Encoding utf8

和路径path有关的cmdlet
split-path
join-path
resolve-path
convert-path
test-path

$dir=get-childitem, 获取$dir的路径

1
2
$dir=get-childitem
$dir.directoryname

1
2
$dir=get-childitem
convert-path $dir[0].psparentpath

统计代码行数

1
dir .\ -Recurse *.php | Get-Content | Measure-Object

发送Post请求

1
2
3
4
5
6
7
$Uri = 'http://codegen.local/index/mybatis/oneToOneAssocQueryGen'
$body=@{
tables=
'abc',
'def'
}
$Result = Invoke-RestMethod -Uri $Uri -Method Post -ContentType "application/json" -Body ($body | convertto-json)

1
2
3
4
5
#thinkphp
public function oneToOneAssocQueryGen(MybatisOneToOneAssocQueryGen $assocQueryGen){
$tables= $this->request->param('tables');
return json($tables);
}

获取unix时间戳

1
[DateTimeOffset]::Now.ToUnixTimeSeconds()

毫秒

1
[DateTimeOffset]::Now.ToUnixTimeMilliseconds()

隐藏错误

1
Remove-Item bucunzai.txt -erroraction 'silentlycontinue'

1
2
3
4
5
6
try{
Remove-Item bucunzai.txt -erroraction
}
catch{
write-output "文件不存在"
}

Powershell如何阻止在脚本中显示错误

设置文件属性,只读,隐藏

1
2
$file = get-item 1.txt
$file.Attributes = "Readonly","system","notcontentindexed","hidden","archive"

PowerShell RegEx match all possible matches
正则匹配到所有结果

1
2
3
$incomingParamsTpl = '<in><erp></erp><name></name></in>'
Select-String '</(.*?)>' -input $incomingParamsTpl -AllMatches |
ForEach-Object { $_.matches } | ForEach-Object { $_.Groups[1].Value } | Where-Object { $_ -ne 'in' }

PowerShell RegEx match all possible matches
Use PowerShell to Create Ordered Dictionary
创建有序字典

1
2
3
4
5
$body = [ordered]@{
dataAdapterType = '2'
dataAdapter = '246d73af3a7944ed86b7da2d03b8473d'
sql = ''
}

startWith不区分大小写

1
$oldUrl.StartsWith($urlItem.oldurl,"CurrentCultureIgnoreCase")