诸如存储计算中 GB , MB , KB 单位等;数组声明中的 1..n 和下标为 -1 的处理;还有所见即所得,通俗易懂的 动词 + 名词 结构的Cmdlet(PowerShell命令的称呼)。 还有自带的文档支持也很是丰富,只要熟练掌握 Get-Help 命令,其他命令的用法均可通过 Get-Help 查到
GB
MB
KB
1..n
-1
Get-Help
良心啊,这个语言竟然是面向对象的 与面向过程相比,面向对象更方便更容易描述现实世界,也算赶上了时髦。
正所谓大树下面好乘凉, PowerShell 绑上 .NET 这个大款了,借助 .NET 平台强大的类库,几乎让一切都成为可能。
PowerShell
.NET
完全兼容 Windows 平台上其它调用,如可执行文件(exe),批处理bat/cmd和VBscript等, 在 Linux 和 macOS 上也能很好地工作。
Windows
Linux
macOS
微软有个优点,与应用相比,它更喜欢做平台。 PowerShell 早已变成一个平台,在 PowerShell 刚发布的第二年,微软的 System Center Operations Manager 和 SharePoint 就提供了针对该平台的组件,后来的活动目录,Hyper-V,Windows Azure,Office 365就更不用说了。除了微软,亚马逊的云平台管理,Dell的out-of-hand 管理,也都提供了基于 PowerShell 的管理组件。 PowerShell 俨然变成了一个标准,变成了一个规范。
下面用一个简单例子说明如何 Get-Help ,设想这样一个场景: 你想通过命令行查看所有进程,你第一个反应应该是用一个跟Process相关的命令来达到此目的,所以你可以会尝试执行:
1234567891011
Get-Command *Process#结果CommandType Name Version Source----------- ---- ------- ------Cmdlet Debug-Process 3.1.0.0 Microsoft.PowerShell.ManagementCmdlet Enter-PSHostProcess 3.0.0.0 Microsoft.PowerShell.CoreCmdlet Exit-PSHostProcess 3.0.0.0 Microsoft.PowerShell.CoreCmdlet Get-Process 3.1.0.0 Microsoft.PowerShell.ManagementCmdlet Start-Process 3.1.0.0 Microsoft.PowerShell.ManagementCmdlet Stop-Process 3.1.0.0 Microsoft.PowerShell.ManagementCmdlet Wait-Process 3.1.0.0 Microsoft.PowerShell.Management
得知处理进程的命令有这些 然后再用 Get-Help Get-Process -full 就能得到 Get-Process 的详细用法以及使用范例
Get-Help Get-Process -full
Get-Process
PowerShell 是一个强类型(变量一旦定义,其本身类型不可改变就是强类型,反之就是弱类型)的动态脚本语言,支持面向对象,支持调用系统API和 .NET 库。 受到了 Python , Ksh , Perl , C# , CL , DCL , SQL , Tcl , Tk , Chef , Puppet 等语言的影响,结合了以上语言的部分特性。
Python
Ksh
Perl
C#
CL
DCL
SQL
Tcl
Tk
Chef
Puppet
PowerShell 代码的外观和操作方式与C#的相似程度最高,不过也有它自己的特色。
与 Python 等语言不同,** PowerShell 的解释器不会考虑代码中的空格或制表符**(这些字符统称空白字符)。这样一来,格式化代码就有很大的自由度,但是遵循某些规则将有助于提高代码的可读性。
PowerShell 代码由一系列语句构成,每条语句可以使用一个分号结束,当然也可以不写。 按照习惯是不写分号的,因此要用换行来区分不同的语句,如果必须写到一行中,那就在每一句后加个分号 。
和C语系的大多数语言类似, PowerShell 是一种块结构的语言,这些块用 { 和 } 来界定,代码块可以包含任意多条语句,或者不包含任何语句,下面的示例还使用了缩进格式,这样能大大提高可读性,实际上编译器会自带缩进代码。一般情况下,每个代码块都有自己的缩进级别,代码块之间还能嵌套。
{
}
123456789
{ <#代码行1#> <#代码行2#> { <#代码行3#> <#代码行4#> } <#代码行5#>;<#代码行6#>;}
当然 PowerShell 的缩进不是强制的。
在 PowerShell 代码中,另一种常见的语句是注释,注释并不是能执行的语句,而是对代码的描述说明性文本。当代码运行时,解释器会忽略这些内容。 代码最好有注释,特别是处理较复杂的工作时,注释可以为正在进行的操作添加提示,例如“这行代码要求用户输入一个字符”、“此段代码是 LNP 编写的”。 PowerShell 有两种添加注释方法
#
<#
#>
#这是一行注释<#这是注释块123ABC#>ls #列出当前目录下的文件和文件夹,是Get-ChildItem的别名#注意下面语句会产生错误<#块注释由"#>"结尾#>
第一个 #> 后面的部分会被认为是 PowerShell 代码,因此出现错误。
还有特别的注意一点,** PowerShell 代码是不区分大小写的**,因此只要拼写正确的命令(或变量),而无需关心大小写即可执行,不过最好还是有一定规范。
PowerShell 像 Python 一样,允许使用控制台直接输入命令进行交互,也可以事先把代码写入一个文件再作为脚本运行。 一个 PowerShell 脚本仅仅是一个包含 PowerShell 代码的文本文件。如果这个文本文件执行, PowerShell 解释器会逐行解释并执行它的的语句。 PowerShell 脚本有点像以前 CMD 控制台上的批处理文件。可以通过非常简单的文本编辑工具创建 PowerShell 脚本。
CMD
PowerShell脚本文件的扩展名是 .ps1
.ps1
PowerShell 一般初始化情况下都会禁止脚本执行。脚本能否执行取决于PowerShell的执行策略。
12345678
PS E:> ./MyScript.ps1无法加载文件 E:MyScript.ps1,因为在此系统中禁止执行脚本。有关详细信息,请参阅 "get-help about_signing"。所在位置 行:1 字符: 15+ .MyScript.ps1 < <<< + CategoryInfo : NotSpecified: (:) [], PSSecurityException + FullyQualifiedErrorId : RuntimeException
只有管理员才有权限更改这个策略。非管理员会报错。
查看脚本执行策略,可以通过在 PowerShell 控制台直接输入: Get-ExecutionPolicy 更改脚本执行策略,可以管理员启动PowerShell,在控制台输入: Set-ExecutionPolicy <策略> 策略|解释 -|- Unrestricted|权限最高,可以不受限制执行任何脚本。 Default|为Powershell默认的策略,即Restricted Restricted|不允许任何脚本执行 AllSigned|所有脚本都必须经过签名才能在运行 RemoteSigned|本地脚本无限制,但是对来自网络的脚本必须经过签名
Get-ExecutionPolicy
Set-ExecutionPolicy <策略>
如果要使用脚本功能又要兼顾安全性,我们就选择RemoteSigned 即在以管理员身份允许的 PowerShell 输入 Set-ExecutionPolicy RemoteSigned
Set-ExecutionPolicy RemoteSigned
123
执行策略可以防止您执行不信任的脚本。更改执行策略可能会使您面临 about_Execution_Policies帮助主题中所述的安全风险。是否要更改执行策略?[Y] 是(Y) [N] 否(N) [S] 挂起(S) [?] 帮助 (默认值为“Y”): y
当您的脚本编写成功后您可能第一次会像下面的方式运行它,也就是只输入脚本的文件名,会报错。
PS E:> MyScript.ps1无法将“MyScript.ps1”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后重试。所在位置 行:1 字符: 13+ MyScript.ps1 < <<< + CategoryInfo : ObjectNotFound: (MyScript.ps1:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundExceptionSuggestion [3,General]: 未找到命令 MyScript.ps1,但它确实存在于当前位置。Windows PowerShell 默认情况下不从当前位置加载命令。如果信任此命令,请改为键入 "./MyScript.ps1"。有关更多详细信息,请参阅 "get-help about_Command_Precedence"。
解决办法很简单,如果脚本在当前工作目录,请在脚本文件明前添加 ./ ,或者使用绝对路径。
./
12345678910111213
PS E:> .\MyScript.ps12019年3月27日 18:33:03C:\Program Files\Common Filesfiles count20PS E:> E:MyScript.ps12019年3月27日 18:33:11C:\Program Files\Common Filesfiles count20
如果想要执行的脚本不是很长,我们甚至可以直接在控制台中要执行的语句重定向给一个脚本文件。
PS E:> '"Hello,World!"' > MyScript.ps1PS E:> ./MyScript.ps1Hello,World!
这样有个缺点,就是您的代码必须放在闭合的引号中。这样的书写方式一旦在脚本内部也有引号时,是一件很痛苦的事。甚至您还可能希望在脚本中换行。下面的Here-strings例子不错,也就是将脚本文件通过 @' '@ 闭合起来。
@' '@
12345678910111213141516
PS E:> @'>> Get-Date>> $Env:CommonProgramFiles>> #Script End>> "files count">> (ls).Count>> #Script Really End>>>> '@ > myscript.ps1>>PS E:> .MyScript.ps12019年3月27日 18:15:10C:\Program Files\Common Filesfiles count20
Here-String以 @' 开头,以 '@ 结束.任何文本都可以存放在里面,哪怕是一些特殊字符,空号,白空格。但是如果您不小心将单引号写成了双引号, PowerShell 将会把里面的变量进行解析。
@'
'@
其实最方便的还是使用文本编辑器直接编写代码,保存成PS1文件,右键即可执行。 这里推荐使用Visual Studio Code(以下简称VSC),VSC提供了PS1的自动补全(安装插件)、语法高亮、自动缩进、格式化代码、断点调试等功能。
变量可以临时保存数据,因此可以把数据保存在变量中,以便进一步操作。 PowerShell 的变量定义非常方便。 我们可以用 $变量名=初值 的方法定义变量,解释器会根据所赋的初值判断变量类型,类似于C#的 var 关键字或C++11中的 auto 关键字 PowerShell 不需要显示地去声明,可以自动创建变量,只须记住变量的前缀为$. 创建好了变量后,可以通过变量名输出变量,也可以把变量名存在字符串中。但是有个例外: 单引号中的字符串不会识别和处理变量名。
$变量名=初值
var
auto
在 PowerShell 中变量名均是以美元符 $ 开始,剩余字符可以是数字、字母、下划线的任意字符,并且PowerShell变量名也对大小写不敏感( $a 和 $A 是同一个变量)。 某些特殊的字符(比如 $ 等)在 PowerShell 中有特殊的用途,一般不推荐使用这些字符作为变量名。当然你硬要使用,请把整个变量名后缀用花括号括起来。
$
$a
$A
PS C:/> ${"I"like $}=5.1PS C:/> ${"I"like $}5.1
不能定义和保留变量名称相同的变量 使用 ls variable: 列出当前使用的所有变量,刚启动的 PowerShell 执行此命令能看到 PowerShell 的所有自动化变量(一旦打开 Powershell 就会自动加载的变量,后面将会详细解释这些变量的作用)
ls variable:
Powershell
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
Name Value---- -----$? True^args {}ConfirmPreference HighConsoleFileNameDebugPreference SilentlyContinueError {}ErrorActionPreference ContinueErrorView NormalViewExecutionContext System.Management.Automation.EngineIntrinsicsfalse FalseFormatEnumerationLimit 4HOME C:\Users\aaaaaHost System.Management.Automation.Internal.Host.InternalHostInformationPreference SilentlyContinueinput System.Collections.ArrayList+ArrayListEnumeratorSimpleMaximumAliasCount 4096MaximumDriveCount 4096MaximumErrorCount 256MaximumFunctionCount 4096MaximumHistoryCount 4096MaximumVariableCount 4096MyInvocation System.Management.Automation.InvocationInfoNestedPromptLevel 0nullOutputEncoding System.Text.ASCIIEncodingPID 8796PROFILE C:\Users\aaaaa\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1ProgressPreference ContinuePSBoundParameters {}PSCommandPathPSCulture zh-CNPSDefaultParameterValues {}PSEdition DesktopPSEmailServerPSHOME C:\Windows\System32\WindowsPowerShell\v1.0PSScriptRootPSSessionApplicationName wsmanPSSessionConfigurationName http://schemas.microsoft.com/powershell/Microsoft.PowerShellPSSessionOption System.Management.Automation.Remoting.PSSessionOptionPSUICulture zh-CNPSVersionTable {PSVersion, PSEdition, PSCompatibleVersions, BuildVersion...}PWD C:\Users\aaaaaShellId Microsoft.PowerShellStackTracetrue TrueVerbosePreference SilentlyContinueWarningPreference ContinueWhatIfPreference False
变量可以自动存储任何 PowerShell 能够识别的类型信息,可以通过 $变量名.GetType() 查看和验证 PowerShell 分配给变量的数据类型
$变量名.GetType()
123456
PS C:/> $num=10PS C:/> $num.gettype() #不区分大小写IsPublic IsSerial Name BaseType-------- -------- ---- --------True True Int32 System.ValueType
如果不想继续使用自定义的变量,可以使用 del variable:变量名 的方法删除变量,注意此处无 $ 符号
del variable:变量名
$a=0$a -eq $nullFalsedel variable:a$a -eq $null True
PowerShell支持的变量类型和C#大体相同(没有了short、uint、ulong等),大多都继承自 System.ValueType 类( .NET类),其基本数据类型包括
System.ValueType
其实 int 、 long 、以及下面的 float 都是 .NET的语法糖,真正的原生类型名是 int32 、 int64 、 single 之类的类名
int
long
float
int32
int64
single
浮点数标准形式( float 和 double ) $+/-m×2^e$ 其中m为尾数,e为阶码,尾数是一个非负数,阶码是一个整数 PowerShell还支持一个特别的浮点数类型 decimal ,其形式为 $+/-m×10^e$
double
decimal
除了数值类型以外,还有3种基本类型
$true
$false
注意 C/C++的 char 仅支持ASCII里面的256个字符, PowerShell 和 C# 的 char 是支持Unicode的 , PowerShell和C#的 string 类型并不是继承自 System.ValuType 类,而是继承自 System.Object 类 ,因此严格来说 string 类型并非是简单类型。 **PowerShell的转义字符是 ` 而不是 \**,这也是和C#的一个区别
char
string
System.ValuType
System.Object
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
#使用charPS D:/>[char]$c="A"$cA#使用boolPS D:/>$boolean=$true$booleanTrue#使用enumenum fruit{ apple banana cherry durian}[fruit]$en=[fruit]::apple$enapple$item="cherry"[fruit]$enu=[fruit]::($item)$enucherry#这种使用方法是错误的PS D:/> [fruit]$enum=bananabanana : 无法将“banana”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。所在位置 行:1 字符: 12+ [fruit]$en=banana+ ~~~~~~ + CategoryInfo : ObjectNotFound: (banana:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException#当尝试使用非枚举值进行赋值时PS D:/> [fruit]$en=[fruit]::peach由于枚举值无效,无法将 Null 转换为类型“fruit”。请指定以下枚举值之一,然后重试。可能的枚举值为“apple,banana,cherry,durian”。所在位置 行:1 字符: 1+ [fruit]$en=[fruit]::peach+ ~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException + FullyQualifiedErrorId : RuntimeExceptionPS D:/> "\n 123 `n 123"<#输出\n 123 123#>PS D:/>$date=get-date$date$date.gettype()<#输出2019年3月28日 19:32:30IsPublic IsSerial Name BaseType-------- -------- ---- --------True True DateTime System.ValueType#>
赋值操作符为 = ,几乎可以把任何数据赋值给一个变量,甚至一条cmdlet命令 ,因为 PowerShell 支持面向对象,对象可以包罗万象。
=
1234567891011121314151617181920
PS D:\powershell\test> $item=lsPS D:\powershell\test> $item 目录: D:\powershell\testMode LastWriteTime Length Name---- ------------- ------ -----a---- 2017/11/24 12:52 136 4-3.cpp-a---- 2019/3/27 15:13 65 anapple.txtPS D:\powershell\test> $item.gettype()IsPublic IsSerial Name BaseType-------- -------- ---- --------True True Object[] System.Array$item为一个对象数组
一般对 PowerShell 变量重新赋值时,变量类型会自动改变,这是弱类型语言的特点; 而 PowerShell 依托的 .NET是强类型的,所以 PowerShell 可以使用强类型。 强类型语言在速度上略逊于弱类型语言,但是强类型定义语言带来的严谨性又能避免不必要的错误。 可以在变量前添加类型限定符使该变量变为强类型,可以确保变量的类型不会随着赋值而改变
[int]$num=123 #正确[int]$num=ls <#错误无法将“System.Object[]”类型的“System.Object[]”值转换为“System.Int32”类型。所在位置 行:1 字符: 1+ [int]$num=ls+ ~~~~~~~~~~~~ + CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException + FullyQualifiedErrorId : RuntimeException#>
PowerShell 能够非常方便地将字符串等基本类型转换成期望的类型。之所以神奇,是因为 PowerShell 本身做了很多辛苦的工作,按照优先级:
void
Boolean
String
Array
Hashtable
PSReference
XmlDocument
Delegate
Enum
Parse()
IConvertible
PSObject
TypeConverter
PSTypeConverter
注意 对浮点数向整数进行类型转换时,会自动四舍五入!! 如果要C++/C#那种向下取整的方法请使用 [math]::Floor() 函数 看几个转换的例子
[math]::Floor()
12345
PS D:/test> $s=12.56PS D:/test> [int]$s13PS D:/test> [convert]::ToInt32($s)13
[convert]::ToInt32() 是 .NET System.Convert 类提供的转换函数 convert 类中的转换函数格式为: TO + 原生类型名() ,这里的原生类型名指的是各个类型实际类名 常用:
[convert]::ToInt32()
System.Convert
convert
TO
原生类型名()
[convert]::ToSingle()
[convert]::ToDouble()
[convert]::ToBoolean()
[convert]::ToString()
convert 类提供了一系列方法来完成不同变量之间的转换,获得函数列表及使用方法请参考微软的 .NET文档 Convert类 方法列表
注意逻辑运算符和比较运算符的写法,不支持 C# 的 && || ! == != < > >= <= 这些运算符
&&
||
!
==
!=
<
>
>=
<=
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
#加 减 乘 除 取余+ - * / %#自增、自减运算符,和C#或C++完全一致++$i$i++$i----$i#且-and#并-or#非-not!#样例$true -and $false -or -not 0!$true#输出TrueFalse#等于 (equal to)-eq#不等于 (not equal to)-nq#大于 (greater than)-gt#大于等于 (greater than or equal to)-ge#小于 (less than)-lt#小于等于 (less than or equal to)-le#对于字符串类型,可以在比较运算符前加i或c表示是否区分大小写,#i表示对大小写不敏感,c表示敏感,不写默认不敏感"a" -eq "A""a" -ceq "A"#输出TrueFalse#判断变量是否为兼容类型(同一类型或其父类型),类型格式为 [类型名]-is#示例$a=0$a -is [int]$b=1,2,3$b -is [array]$a -is [ValueType]#输出TrueTrueTrue # System.Int32类继承自System.ValueType类,因此int是其父类型ValueType的子类型
if 和 else 用法和C#完全一样,除了大括号不允许省略,多分支时还多了个 elseif 可用,和 Python 的 elif 作用相同
if
else
elseif
elif
if($true -and $true) { $a=0}elseif($a -eq $b) { $a=1}else { $a=2}
PowerShell的 switch 非常灵活,使用起来较为方便 相对C#或C++,PowerShell的switch不需要写`case:``,但是必须写大括号
switch
$a="Beijing"switch($a) { "Beijing" {$res="北京"} "Shanghai" {$res="上海"}}
默认比较运算符为 -eq ,你也可以使用下面的例子自定义比较条件,必须保证表达式返回boolen类型($true和$false)
-eq
12345678910
$v=18switch($v){ {$_ -lt 10} {"小于10"} # $_ 表示当前的传入的变量 直接写的字符串会被输出 10 {"等于10"} {$_ -gt 10} {"小于10"}}<#输出大于10#>
接下来介绍循环
PowerShell 的 for 循环类似于 C# ,看一个样例:
for
1234
for($i=0;$i -lt 10;$i++){ Write-Output "Hello"}
Do 和 While 可能产生死循环,为了防止死循环的发生,因此我们必须确切的指定循环终止的条件。指定了循环终止的条件后,一旦条件不满足就会退出循环。 do-while() 会先执行再去判断,能保证循环至少执行一次。
Do
While
do-while()
do { $n=Read-Host "请输入数字"} while($n -ne 0)<#输出请输入数字: 1请输入数字: 2请输入数字: s请输入数字: 0#>
123456789101112
$n=5while($n -gt 0){ $n $n=$n-1}#输出54321
使用 continue 关键字,可以终止当前循环,跳过 continue 后其它语句,重新下一次循环。 跳出循环语句使用 break 关键字
continue
break
1234567891011121314151617181920212223242526272829
$n=1while($n -lt 6){ if($n -eq 4) { $n=$n+1 continue } else { $n } $n=$n+1}1235$n=1while($n -lt 6){ if($n -eq 4) { break } $n $n++}
还有一种循环 foreach ,等到我们讲到数组再说
foreach
在 PowerShell 中创建数组可以使用逗号
PS C:/Powershell> $nums=2,0,1,2PS C:/Powershell> $nums2012
对于连续的数字数组可以使用一个更快捷的方法:
1234567
PS C:/Powershell> $nums=1..5PS C:/Powershell> $nums12345
像变量一样,如果数组中元素的类型为弱类型,默认可以存储不同类型的值。
123456789101112131415161718192021222324252627282930313233
PS C:/Powershell> $array=1,"2019",([Guid]::NewGuid()),(get-date)PS C:/Powershell> $array12019Guid----ea5f17c6-c0a2-42ba-9de4-e4d03bebffafDisplayHint : DateTimeDate : 2019/3/29 0:00:00Day : 29DayOfWeek : FridayDayOfYear : 88Hour : 23Kind : LocalMillisecond : 120Minute : 23Month : 3Second : 39Ticks : 636894986191207086TimeOfDay : 23:23:39.1207086Year : 2019DateTime : 2019年3月29日 23:23:39PS C:/Powershell> $array|foreach{$_.gettype()}#查看数组各元素类型IsPublic IsSerial Name BaseType-------- -------- ---- --------True True Int32 System.ValueTypeTrue True String System.ObjectTrue True Guid System.ValueTypeTrue True DateTime System.ValueType
对数组元素可以查看它的公有属性,比如长度 只需要输入 $数组名.Count 即可显示数组长度
$数组名.Count
PS C:/Powershell> $a=@()PS C:/Powershell> $a -is [array]TruePS C:/Powershell> $a.Count0
PS C:Powershell> $a=,"moss"PS C:Powershell> $a -is [array]TruePS C:Powershell> $a.Count1
将数组作为单独一行将会自动遍历这个数组的所有元素
PS C:/> $a=1..10PS C:/> $a12345678910
PS C:/> $a=1..5PS C:/> for($i=0;$i -lt 5;$i++) {>> $a[$i] }12345}
还有一种遍历的方法,用到了之前提到的 foreach 语句 意思是使用变量 $n 对 $a 元素进行迭代,这实际上是一种对可迭代对象的访问算法 在 C# 也有这种语法
$n
$a="A","B","C","D","E"foreach($n in $a){ $n+" "+$n}#输出A AB BC CD DE E
foreach 还有一种遍历的写法
这里我们需要先了解一下 管道 管道的符号 | 管道允许将它左侧命令的输出结果发送到右侧做命令的参数 管道并不是什么新事物,以前的Cmd控制台也有重定向的命令,例如Dir | More可以将结果分屏显示。 传统的Cmd管道是基于文本的,但是 PowerShell 是基于对象的
列出当前目录下的目录和文件,然后根据文件名降序排列,再投影(数据库术语)文件名,文件大小,文件的修改时间:
PS D:/test> ls | Sort-Object -Descending Name | Select-Object Name,Length,LastWriteTime 目录: D:/testName Length LastWriteTime---- ------ -------------out.txt 523 2019/2/24 22:46:35lang.json 6415 2019/2/16 23:49:24anapple.txt 65 2019/3/27 15:13:524-3.cpp 136 2017/11/24 12:52:28
可迭代对象(比如数组)可以由管道送到一些命令上进一步处理 foreach 就可以接受管道送来的可迭代对象,并进行遍历
$array="A","B","C","D","E"$array|foreach{ $_+"s"}#输出AsBsCsDsEs
PS C:/Powershell> $books="A1","B2","C3"PS C:/Powershell> $books[($books.Count)..0]C3B2A1
与C#相同,数组的元素可以使用索引寻址,第一个元素的索引为0,第i个元素的索引为i-1,最后一个元素的索引为Count-1,但是 PowerShell 为了使用方便,直接可以将 -1 作为最后的一个元素的索引(参考了 Python 的语法)
PS C:/Powershell> $books="1A","2B","3C"PS C:/Powershell> $books[0]1APS C:/Powershell> $books[1]2BPS C:/Powershell> $books[($book.Count-1)]3CPS C:/Powershell> $books[-1]3C
PS C:/Powershell> $result=lsPS C:/Powershell> $result[0,3,5,12] Directory: C:PowershellMode LastWriteTime Length Name---- ------------- ------ ----d---- 2011/11/23 17:25 ABC-a--- 2011/11/24 20:04 26384 a.txt-a--- 2011/11/24 20:27 12060 alias.ps1-a--- 2011/11/24 17:37 7420 name.html
因为PowerShell数组在内存中是顺序存储的,所以数组的大小必须是确定的,这样才方便分配存储空间,所以给数组增加元素其实相当于创建一个新的数组,只不过之后会把原来的副本删除。在当前数组追加元素可以使用 += 操作符。
+=
PS C:/Powershell> $books="A1","B2","C3"PS C:/Powershell> $books+="D4"PS C:/Powershell> $booksA1B2C3D4
采用截断重连法删除指定元素
PS C:/Powershell> $num=1..4PS C:/Powershell> $num1234PS C:/Powershell> $num=$num[0..1]+$num[3] #相当于删掉了第三项PS C:/Powershell> $num124
数组属于引用类型,使用默认的的赋值运算符在两个变量之间赋值只是复制了一个引用,两个变量共享同一份数据。这样的模式有一个弊病如果其中一个改变也会株连到另外一个。所以复制数组最好使用 Clone() 方法( System.Array 类的成员函数),除非有特殊需求。
Clone()
System.Array
1234567891011121314151617
PS C:/Powershell> $chs=@("A","B","C")PS C:/Powershell> $chsBak=$chsPS C:/Powershell> $chsBak[1]="H"PS C:/Powershell> $chsAHCPS C:/Powershell> $chs.Equals($chsBak)TruePS C:/Powershell> $chsNew=$chs.Clone()PS C:/Powershell> $chsNew[1]="Good"PS C:/Powershell> $chs.Equals($chsNew)FalsePS C:/Powershell> $chsAHC
PowerShell 数组一般具有多态性,如果你不指定元素的具体类型,解释器会自动选择合适的类型存储每个元素。如果要统一限制所有元素的类型,可是使用类型名和一对方括号作为数组变量的类型。这样每当赋值时,会自动类型检查。如果目标数据类型不能转换成功,就会抛出一个异常,这样的数组被称为强类型数组 定义方法 [类型[]]$数组名=初值
[类型[]]$数组名=初值
PS C:/Powershell> [int[]] $nums=@()PS C:/Powershell> $nums+=2012PS C:/Powershell> $nums+=12.3PS C:/Powershell> $nums+="999"PS C:/Powershell> $nums+="can not convert"Cannot convert value "can not convert" to type "System.Int32". Error: "Input string was not in a correct format."At line:1 char:6+ $nums <<<< +="can not convert" + CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException + FullyQualifiedErrorId : RuntimeException
当我们把一个命令的执行结果保存到一个变量中,可能会认为变量存放的是纯文本。 但是,事实上 PowerShell 会把文本按每一行作为元素存为数组。如果一个命令的返回值不止一个结果时, PowerShell 也会自动把结果存储为数组
12345678910111213141516171819202122232425262728293031323334353637383940414243
PS C:/Powershell> $IPcfg=ipconfigPS C:/Powershell> $IPcfg<#输出Windows IP 配置以太网适配器 以太网: 媒体状态 . . . . . . . . . . . . : 媒体已断开连接 连接特定的 DNS 后缀 . . . . . . . : lan无线局域网适配器 本地连接* 1: 媒体状态 . . . . . . . . . . . . : 媒体已断开连接 连接特定的 DNS 后缀 . . . . . . . :无线局域网适配器 本地连接* 2: 连接特定的 DNS 后缀 . . . . . . . : 本地链接 IPv6 地址. . . . . . . . : **** IPv4 地址 . . . . . . . . . . . . : **** 子网掩码 . . . . . . . . . . . . : **** 默认网关. . . . . . . . . . . . . :以太网适配器 VMware Network Adapter VMnet8: 连接特定的 DNS 后缀 . . . . . . . : 本地链接 IPv6 地址. . . . . . . . : fe80::f88d:cd97:5343:9713%16 IPv4 地址 . . . . . . . . . . . . : **** 子网掩码 . . . . . . . . . . . . : **** 默认网关. . . . . . . . . . . . . :无线局域网适配器 WLAN: 连接特定的 DNS 后缀 . . . . . . . : **** 本地链接 IPv6 地址. . . . . . . . : fe80::954:3964:3731:997e%18 IPv4 地址 . . . . . . . . . . . . : **** 子网掩码 . . . . . . . . . . . . : **** 默认网关. . . . . . . . . . . . . : ****#>PS C:/Powershell> $IPcfg.Count37
判断一个变量是否为数组
PS C:/Powershell> $ip=ipconfigPS C:/Powershell> $ip -is [array]TruePS C:/Powershell> "abac" -is [array]FalsePS C:/Powershell> $str="字符串"PS C:/Powershell> $str.ToCharArray() -is [array] #转换为字符数组True
为什么不愿把IPconfig返回的结果称为对象,因为它不是真正Cmdlet命令(事实上ipconfig是一个单独的程序),真正的 PowerShell 命令返回的数组元素可不止一个字符串,它是一个内容丰富的对象。
PS D:/test> $list=lsPS D:/test> $list 目录: D:/testMode LastWriteTime Length Name---- ------------- ------ -----a---- 2017/11/24 12:52 136 4-3.cpp-a---- 2019/3/27 15:13 65 anapple.txtPS D:/test> $list.gettype()IsPublic IsSerial Name BaseType-------- -------- ---- --------True True Object[] System.ArrayPS D:/test> foreach($i in $list){$i.name}4-3.cppanapple.txtPS D:/test> $list[0].gettype()IsPublic IsSerial Name BaseType-------- -------- ---- --------True True FileInfo System.IO.FileSystemInfo
上面的例子中数组的每一个元素存放的是一个 System.IO.DirectoryInfo 对象。 当我们输出这些对象时, PowerShell 会自动帮我们把它转换成友好的文本格式。 对于任何一个对象都可以使用 Format-List * 来查看它所有的属性和方法。
System.IO.DirectoryInfo
Format-List *
123456789101112131415161718192021222324252627282930313233343536373839404142
PS D:/test> $list[0]|fl * # "|"符号是管道符,将左边返回结果做参数发送到右侧,fl是Format-List的简称PSPath : Microsoft.PowerShell.Core\FileSystem::D:test\4-3.cppPSParentPath : Microsoft.PowerShell.Core\FileSystem::D:\testPSChildName : 4-3.cppPSDrive : DPSProvider : Microsoft.PowerShell.Core\FileSystemPSIsContainer : FalseMode : -a----VersionInfo : File: D:\test\4-3.cpp InternalName: OriginalFilename: FileVersion: FileDescription: Product: ProductVersion: Debug: False Patched: False PreRelease: False PrivateBuild: False SpecialBuild: False Language:BaseName : 4-3Target : {}LinkType :Name : 4-3.cppLength : 136DirectoryName : D:\testDirectory : D:\testIsReadOnly : FalseExists : TrueFullName : D:\test\4-3.cppExtension : .cppCreationTime : 2019/3/27 15:07:32CreationTimeUtc : 2019/3/27 7:07:32LastAccessTime : 2019/3/27 15:07:32LastAccessTimeUtc : 2019/3/27 7:07:32LastWriteTime : 2017/11/24 12:52:28LastWriteTimeUtc : 2017/11/24 4:52:28Attributes : Archive
函数是自定义的 Powershell 代码,有三个原则:
函数可以在文本编辑器上编写,写完以后复制进 PowerShell 控制台即可。如果控制台设置为快速编辑模式,从记事本复制后,直接在控制台鼠标右键即可完成粘贴(Windows 10默认开启了快速编辑模式)
function FuncName(args[]) #括号可省略{ <#代码段#>}
PS C:/PowerShell> function MyPing>> {>> PING.EXE -n 1 $args>> }PS C:/PowerShell>
我们可以将一个函数定义在一行上,但是这样阅读和理解起来就不方便,所以要在每条命令后加分号进行分割(最后一句可以不写 ; )
;
12
PS C:/PowerShell> function cd...{ cd.. ; cd.. }PS C:/PowerShell> cd...
假如 PowerShell 不支持 Get-SystemVersion 命令,你可以通过定义函数实现这个功能:
Get-SystemVersion
function get-systemversion{ $psversiontable.BuildVersion}Get-SystemVersionMajor Minor Build Revision----- ----- ----- --------10 0 17134 590
如果要更新已经定义好的函数,简单的方法是重新定义,这样新的定义会覆盖旧的定义。但是如果函数代码没有保存副本,可以先将函数定义导出到ps文件,然后就可以编辑了。
1234567891011121314
PS C:/PowerShell> function MyPing>> {>> PING.EXE -n 1 $args>> }PS C:/PowerShell> $function:MyPing | Out-File myPing.ps1PS C:/PowerShell> $function:MyPingPING.EXE -n 1 $argsPS C:/PowerShell> $function:MyPing | Out-File myPing.ps1PS C:/PowerShell> .myPing.ps1必须指定 IP 地址。PS C:/PowerShell> notepad.exe $$
控制台定义的函数只会在当前会话生效,一旦控制台退出,会自动消失。在不关闭控制台的条件下删除一个已经定义好的函数,可是使用虚拟驱动器的方法:
function cc{"hello"}PS C:/> cchelloPS C:/> del function:ccPS C:/> cccc : 无法将“cc”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。所在位置 行:1 字符: 1+ cc+ ~~ + CategoryInfo : ObjectNotFound: (cc:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException
用于脚本文件的编写
PowerShell提供了 Read-Host 命令,可以接收返回用户在控制台输入的字符
Read-Host
$name=read-host "请输入你的名字" #会把提示信息打印到PS控制台,也可以不写提示信息<#执行+输入 结果:请输入你的名字: Nougat #>$nameNougat
有两种输出命令 Write-Host 和 Write-Output 若输出字符串不包含空白字符可以不加引号
Write-Host
Write-Output
当需要展示一个特定信息,比如使用其他颜色来吸引人们的注意力的时候,可使用 Write-Host 命令 Write-Host 和其他Cmdlets一样使用管道,但是它不放置任何数据道管道中。反而会直接写到宿主应用程序的界面。正如此,可以使用 -ForegroundColor 和 -BackgroundColor 参数将前景和背景设置为其他颜色:
-ForegroundColor
-BackgroundColor
write-host "啊哈" -ForegroundColor White -BackgroundColor Red啊哈
注: 不是每个使用PowerShell的应用程序都支持其他颜色,也并不是每个应用程序都支持所有颜色 。 该输出方法 不适用于常规的输出结果 ,因为 Write-Host 命令输出到屏幕的任何东西都无法被捕捉。若执行远程命令或无人值守命令(纯自动化), Write-Host 可能不会按照你的预期工作。因此,此命令仅仅用于与人进行直接交互。
Write-Output 命令会将对象发送给管道。由于它不会直接发送到显示界面,所以不允许你指定其他任何的颜色。
它是 PowerShell 默认使用的一个Cmdlets,默认输出方式即使用该命令,即使你没有指定, PowerShell 会在底层将信息传递给 Write-Output 命令(就是一行直接写一个变量就能直接输出的情况),另外这个命令还有两个别名 write 和 echo
write
echo
write-host ACB #无空白字符可以不写引号 ACBwrite "ABC"ABCecho "ABD"ABD
Write-Output 输出基本过程为:
Hello World!
Out-Default
Out-Host
还有一点,在输出多个对象时, Write-Host 会以空格隔开各对象 Write-Output 会以换行隔开各对象
write-host "ABC" "23232"ABC 23232write-output "ABC" "23232"ABC 23232
Write-Warning/Verbose/Debug/Error
具体参考: 微软官方文档
PowerShell 函数可以接受参数,并对参数进行处理。函数的参数有3个特性:
$args
给一个函数定义参数最简单的是使用 $args 这个内置的参数。它可以识别任意个参数。尤其适用那些参数可有可无的函数。
123456789101112131415161718192021222324252627282930
function sayHello{ if($args.Count -eq 0) { "No argument!" } else { $args | foreach {"Hello,$($_)"} }}#无参调用sayhello#输出No argument!#一参调用sayhello "World!" #也可以写成sayhello("World!")#输出Hello,World!#多参数调用$str="it's me."sayhello 123 "aha" $str #如果字符串不包含空白字符(比如空格),引号可以不写<#输出Hello,123Hello,ahaHello,it's me.#>
因为 $arg 是一个数组,可以用它很方便的写出求和函数
$arg
function Add{ $sum=0 $args | foreach {$sum=$sum+$_} $sum}Add 10 7 3 100#120
function StringContact($str1,$str2){ return $str1+$str2} StringContact LN P#StringContact -str1 word -str2 press#StringContact("word","press")LNPwordpress
function stringContact($str1="LN",$str2="P"){ return $str1+$str2}stringContactLNP
通过之前的例子发现将用户的参数传递给函数显得比较混乱。罪魁祸首就是 PowerShell 的参数解释器,它可以自动处理和分配参数给函数。 函数的参数解释器比较傲慢,它对你提供的参数的信息完全不关心。它只会粗略地将参数进行分割,并且最大限度的进行自动类型转换。事实上,这种类型转换很多时候并不完美。所以 最好提前能够对参数进行强类型限制
下面的函数执行后,会抛出异常 因为 subtract 的参数定义了强类型,参数的类型可能引起函数的处理结果改变。
subtract
123456789101112131415161718192021222324252627
function subtract([int]$value1,[int]$value2){ return $value1-$value2}subtract LN P#执行结果报错subtract : 无法处理对参数“value1”的参数转换。无法将值“LN”转换为类型“System.Int32”。错误:“输入字符串的格式不正确。”所在位置 行:1 字符: 10+ subtract LN P+ ~~ + CategoryInfo : InvalidData: (:) [subtract],ParameterBindingArgumentTransformationException + FullyQualifiedErrorId : ParameterArgumentTransformationError,subtractsubtract 8.1 7.90<#结果为0,这是因为PowerShell对结果整型化时进行了四舍五入但是如果将上面的函数的参数定义为Double型#>function subtract([double]$value1,[double]$value2){ return $value1-$value2}subtract 8.1 7.90.199999999999999<#输出 0.199999999999999的原因就是 .NET使用IEEE754标准存储浮点数,由于这些小数转化二进制会无限循环,会根据一定精度截取尾数,这个问题引发了这种奇怪的结果,其实著名的0.1+0.2!=0.3也是这个原因导致的#>
函数的参数解释器会自动尝试将字符串转换成日期类型,如果转换失败就是抛出异常 看下面的例子
123456789101112131415161718
function DayOfWeek([datetime]$date){ return $date.DayOfWeek}DayofWeek '1927-8-1'MondayDayofWeek 2008-8-1FridayDayofWeek 'abc'DayOfWeek : 无法处理对参数“date”的参数转换。无法将值“abc”转换为类型“System.DateTime”。错误:“该字符串未被识别为有效的 DateTime。有一个未知单词(从索引 0 处开始)。”所在位置 行:1 字符: 12+ DayofWeek 'abc'+ ~~~~~ + CategoryInfo : InvalidData: (:) [DayOfWeek],ParameterBindingArgumentTransformationException + FullyQualifiedErrorId : ParameterArgumentTransformationError,DayOfWeek
Powershell 函数最简单的参数类型为布尔类型,除了使用 Bool 类型,也可以使用 Switch 关键字。 下面的函数逆转字符串,但是可以通过 $try 参数进行控制,如果没有指定 $try 的值,默认值为 $false
Bool
Switch
$try
12345678910111213141516171819
function tryReverse( [switch]$try , [string]$source ) #此处switch完全可以换成bool{ [string]$target="" if($try) { for( [int]$i = $source.length -1; $i -ge 0 ;$i--) { $target += $source[$i] } return $target } return $source}tryReverse -source www.google.comtryReverse -try $true -source www.google.com#输出www.google.commoc.eloog.www
PowerShell 不像其它的编程语言,它的函数可以有多个返回值。如果你直接调用函数,返回值会在控制台输出。当然你也可以将结果存储在一个变量中进一步处理 下面的例子演示返回一个值:
function Square([double]$num){ return $num*$num}#在控制台输出结果Square 9.8797.4169 #将结果赋值给变量$value=Square 9.87$value97.4169 #返回值为Double类型$value.GetType().FullNameSystem.Double
下面的例子演示返回多个值
function gbMeasure($amount){ "$amount GB=$($amount) GB" "$amount GB=$($amount*1gb/1mb) MB" "$amount GB=$($amount*1gb/1kb) KB" "$amount GB=$($amount*1gb) B"} #函数返回4个值gbMeasure 11 GB=1 GB1 GB=1024 MB1 GB=1048576 KB1 GB=1073741824 B #将所有的返回值存储在一个变量中$result=gbMeasure 1$result 1 GB=1 GB1 GB=1024 MB1 GB=1048576 KB1 GB=1073741824 B #所有的返回值会自动存储在一个数组中$result=gbMeasure 1$result.GetType().NameObject[] #通过索引访问每个返回值$result=gbMeasure 1$result[3]1 GB=1073741824 B
总结一下,如果一个函数返回一个值,像其它编程语言一样,这个值包括它的类型信息会直接返回。但是如果遇到多个返回值,PowerShell会将所有的返回值自动构造成一个对象数组。 可以通过索引访问数组
Powershell 会将函数中所有的输出作为返回值,但是也可以通过return语句指定具体的返回值。 Return 语句会将指定的值返回,同时也会中断函数的执行, return后面的语句会被忽略
看一个例子
function test($num){ 1 9 return 10 4 6}test1910<# 1 和 9 作为输出会返回return语句中的10 也会返回return 语句后的4和6会被忽略#>
一个函数返回了一个值还是多个值,是可以验证的。下面的例子会产生随机数,如果没有指定个数,默认会返回一个随机数,否则会返回指定个数的随机数
function lottery([int]$number=1){ $rand = New-Object system.random for ($i=1; $i -le $number; $i++) { $rand.next(1,50) }}# 参数为空时,返回值不是数组:$result = lottery$result -is [array]False# 如果指定多个随机数时,返回值是数组类型:$result = lottery 10$result -is [array]True$result.count10
函数默认会将函数中的所有输出作为函数的返回值返回,这样很方便。但有时可能会将不必要的输出误以为返回值。写脚本程序时,可能需要自定义一些函数,这个函数可能只需要一个返回值,但是为了提高函数的可读性,可能会在函数增加一些注释输出行,或者使用 write-host
write-host
1234567891011121314151617181920212223242526272829303132
function Test(){ "Try to calculate." "3.1415926" "Done."} #保存在变量中输出,$value=Test$value#输出Try to calculate.3.1415926Done. #如果要过滤注释,只输出,不作为返回值,#可以使用Write-Host命令function Test(){ Write-Host "Try to calculate." "3.1415926" Write-Host "Done."}# 在变量值中保存返回值,在控制台输出注释行$value=Test#控制台输出Try to calculate.Done. # 测试返回值$value3.1415926
恭喜你!到此 PowerShell 基础入门算是完成了! 之后将介绍 PowerShell 的进阶使用
网络安全协会网站的搭建(一)
网络安全协会网站的搭建一个网络安全协会要体现自己的特色,必须要有自己的网站才行啊特别是看了ACM协会的网站之后,更加坚定了开发的想法所以这个项目就出现了 Vue.js 与 Node...
math