PowerShell命令与脚本(3)——变量
PowerShell定义变量
变量可以临时保存数据,因此可以把数据保存在变量中,以便进一步操作。
powershell 不需要显示地去声明,可以自动创建变量,只须记住变量的前缀为$.
创建好了变量后,可以通过变量名输出变量,也可以把变量名存在字符串中。但是有个例外单引号中的字符串不会识别和处理变量名。
1、选择变量名
在powershell中变量名均是以美元符”$”开始,剩余字符可以是数字、字母、下划线的任意字符,并且powershell变量名大小写不敏感($a和$A 是同一个变量)。
某些特殊的字符在powershell中有特殊的用途,一般不推荐使用这些字符作为变量名。当然你硬要使用,请把整个变量名后缀用花括号括起来。
2、赋值和返回值
赋值操作符为“=”,几乎可以把任何数据赋值给一个变量,甚至一条命令,为什么,因为Powershell支持对象,对象可以包罗万象。
3、给多个变量赋值
赋值操作符不仅能给一个变量赋值,还可以同时给多个变量赋相同的值。
4、交换变量的值
要交换两个变量的值,传统的程序语言至少需要三步,并且还需定义一个中间临时变量。
在powershell中,交换两个变量的值,这个功能变得非常简单。
5、查看正在使用的变量
Powershell将变量的相关信息的记录存放在名为variable:的驱动中。如果要查看所有定义的变量,可以直接遍历variable:
ls(或dir) variable: 或者Get-Variable
6、验证变量是否存在
验证一个变量是否存在,仍然可以象验证文件系统那样,使用Test-Path。为什么?因为变量存在变量驱动器中。
7、删除变量
因为变量会在powershell退出或关闭时,自动清除。一般没必要删除,但是你非得删除,也可以象删除文件那样删除它。
8、使用专用的变量命令
为了管理变量,powershell提供了五个专门管理变量的命令Clear-Variable,Get-Variable,New-Variable,Remove-Variable,Set-Variable。因为虚拟驱动器variable:的存在,clear,remove,set打头的命令可以被代替。但是Get-Variable,New-Variable。却非常有用new-variable可以在定义变量时,指定变量的一些其它属性,比如访问权限。同样Get-Variable也可以获取这些附加信息。
变量写保护
可以使用New-Variable 的option选项 在创建变量时,给变量加上只读属性,这样就不能给变量重新赋值了。
例如,创建一个num变量,强制赋值为100,并设置为只读属性。
New-Variable num -Value 100 -Force -Option readonly
但是可以通过删除变量,再重新创建变量更新变量内容。也可以强制赋值。
有没有权限更高的变量,有,那就是:选项Constant,常量一旦声明,不可修改
变量描述
在New-Variable 可以通过-description 添加变量描述,但是变量描述默认不会显示,可以通过Format-List 查看。
PowerShell自动化变量
Powershell 自动化变量 是那些一旦打开Powershell就会自动加载的变量。
这些变量一般存放的内容包括
① 用户信息:例如用户的根目录$home
② 配置信息:例如powershell控制台的大小,颜色,背景等。
③ 运行时信息:例如一个函数由谁调用,一个脚本运行的目录等。
powershell中的某些自动化变量只能读,不能写。例如:$Pid。
自动变量列表:
$$
包含会话所收到的最后一行中的最后一个令牌。
$?
包含最后一个操作的执行状态。如果最后一个操作成功,则包含 TRUE,失败则包含 FALSE。
$^
包含会话所收到的最后一行中的第一个令牌。
$_
包含管道对象中的当前对象。在对管道中的每个对象或所选对象执行操作的命令中,可以使用此变量。
$Args
包含由未声明参数和/或传递给函数、脚本或脚本块的参数值组成的数组。
在创建函数时可以声明参数,方法是使用 param 关键字或在函数名称后添加以圆括号括起、逗号
分隔的参数列表。
$ConsoleFileName
包含在会话中最近使用的控制台文件 (.psc1) 的路径。在通过 PSConsoleFile 参数启动
Windows PowerShell 或使用 Export-Console cmdlet 将管理单元名称导出到控制台文件
时,将填充此变量。
在使用不带参数的 Export-Console cmdlet 时,它自动更新在会话中最近使用的控制台文件。
可以使用此自动变量确定要更新的文件。
$Error
包含错误对象的数组,这些对象表示最近的一些错误。最近的错误是该数组中的第一个错误对象
($Error[0])。
$Event
包含一个 PSEventArgs 对象,该对象表示一个正在被处理的事件。
此变量只在事件注册命令(例如 Register-ObjectEvent)的 Action 块内填充。
此变量的值是 Get-Event cmdlet 返回的同一个对象。
因此,可以在 Action 脚本块中使用 $Event 变量的属性(例如 $Event.TimeGenerated)。
$EventSubscriber
包含一个 PSEventSubscriber 对象,该对象表示正在被处理的事件的事件订阅者。
此变量只在事件注册命令的 Action 块内填充。此变量的值
是 Get-EventSubscriber cmdlet 返回的同一个对象。
$ExecutionContext
包含一个 EngineIntrinsics 对象,该对象表示 Windows PowerShell 主机的执行上下文。
可以使用此变量来查找可用于 cmdlet 的执行对象。
$False
包含 FALSE。可以使用此变量在命令和脚本中表示 FALSE,而不是使用字符串”false”。如果
该字符串转换为非空字符串或非零整数,则可将该字符串解释为 TRUE。
$ForEach
包含 ForEach-Object 循环的枚举数。可以对 $ForEach 变量的值使用枚举数的属性和方法。
此变量仅在运行 For 循环时存在,循环完成即会删除。
$Home
包含用户的主目录的完整路径。此变量等效于 %homedrive%%homepath% 环境变量。
$Host
包含一个对象,该对象表示 Windows PowerShell 的当前主机应用程序。可以使用此变量在命
令中表示当前主机,或者显示或更改主机的属性,如 $Host.version、$Host.CurrentCulture
或 $host.ui.rawui.setbackgroundcolor(“Red”)。
$Input
一个枚举数,它包含传递给函数的输入。$Input 变量区分大小写,只能用于函数和脚本块。(脚
本块本质上是未命名的函数。)在函数的 Process 块中,$Input 变量包含当前位于管道中的对
象。在 Process 块完成后,$Input 的值为 NULL。如果函数没有 Process 块,则 $Input
的值可用于 End 块,它包含函数的所有输入。
$LastExitCode
包含运行的最后一个基于 Windows 的程序的退出代码。
$Matches
$Matches 变量与 -match 和 -not match 运算符一起使用。
将标量输入提交给 -match 或 -notmatch 运算符时,如果检测到匹配,则会返回一个布尔值,
并使用由所有匹配字符串值组成的哈希表填充 $Matches 自动变量。有关 -match 运算符的详细
信息,请参阅 about_comparison_operators。
$MyInvocation
包含一个对象,该对象具有有关当前命令(如脚本、函数或脚本块)的信息。可以使用该对象中的
信息(如脚本的路径和文件名 ($myinvocation.mycommand.path) 或函数的名称
($myinvocation.mycommand.name))来标识当前命令。对于查找正在运行的脚本的名称,这非常有用。
$NestedPromptLevel
包含当前提示级别。值 0 指示原始提示级别。该值在进入嵌套级别时递增,在退出嵌套级别时递减。
例如,在使用 $Host.EnterNestedPrompt 方法时,Windows PowerShell 会出现嵌套命令
提示符。在 Windows PowerShell 调试程序中到达断点时,Windows PowerShell 也会出现嵌
套命令提示符。
在进入嵌套提示时,Windows PowerShell 暂停当前命令,保存执行上下文,并递增
$NestedPromptLevel 变量的值。要创建更多嵌套命令提示符(最多 128 级)或返回到原始命
令提示符,请完成命令,或键入”exit”。
$NestedPromptLevel 变量有助于跟踪提示级别。可以创建包含此值的备用 Windows
PowerShell 命令提示符,以使此值始终可见。
$NULL
包含 NULL 或空值。可以在命令和脚本中使用此变量表示 NULL,而不是使用字符串”NULL”。
如果该字符串转换为非空字符串或非零整数,则可将该字符串解释为 TRUE。
$PID
包含承载当前 Windows PowerShell 会话的进程的进程标识符 (PID)。
$Profile
包含当前用户和当前主机应用程序的 Windows PowerShell 配置文件的完整路径。可以在命令
中使用此变量表示配置文件。例如,可以在命令中使用此变量确定是否已创建某个配置文件:
test-path $profile
也可以在命令中使用此变量创建配置文件:
new-item -type file -path $pshome -force
此外,还可以在命令中使用此变量在记事本中打开配置文件:
notepad $profile
$PSBoundParameters
包含活动参数及其当前值的字典。只有在声明参数的作用域(如脚本或函数)中,
此变量才有值。可以使用此变量显示或更改参数的当前值,也可以将参数值传递给
其他脚本或函数。
$PsCmdlet
包含一个对象,该对象表示正在运行的 cmdlet 或高级函数。
可以在 cmdlet 或函数代码中使用该对象的属性和方法来响应使用的条件。例如,
ParameterSetName 属性包含正在使用的参数集的名称,而 ShouldProcess 方法将 WhatIf
和 Confirm 参数动态添加到 cmdlet。
有关 $PSCmdlet 自动变量的详细信息,请参阅 about_Functions_Advanced。
$PsCulture
包含操作系统中当前所用的区域性的名称。区域性确定数字、货币和日期等项的显示格式。这是系
统的 System.Globalization.CultureInfo.CurrentCulture.Name 属性的值。要获取系统
的 System.Globalization.CultureInfo 对象,请使用 Get-Culture cmdlet。
$PSDebugContext
在调试期间,此变量包含有关调试环境的信息。在其他时间,此变量包含 NULL 值。因此,可以使
用此变量指示调试程序是否拥有控制权。填充之后,此变量包含一个具有 Breakpoints 和
InvocationInfo 属性的 PsDebugContext 对象。InvocationInfo 属性有多个十分有用的
属性,包括 Location 属性。Location 属性指示正在调试的脚本的路径。
$PsHome
包含 Windows PowerShell 的安装目录的完整路径(通常为
%windir%System32WindowsPowerShellv1.0)。可以在 Windows PowerShell 文件
的路径中使用此变量。例如,下面的命令在概念性帮助主题中搜索”variable”一词:
select-string -pattern variable -path $pshome*.txt
$PSScriptRoot
包含要从中执行脚本模块的目录。
通过此变量,脚本可以使用模块路径来访问其他资源。
$PsUICulture
包含操作系统中当前所用的用户界面 (UI) 区域性的名称。UI 区域性确定哪些文本字符串用于用户
界面元素(如菜单和消息)。这是系统的
System.Globalization.CultureInfo.CurrentUICulture.Name 属性的值。
$PsVersionTable
包含一个只读哈希表,该哈希表显示有关在当前会话中运行的 Windows PowerShell 版本的详
细信息。
该表包括下列项:
CLRVersion: 公共语言运行时 (CLR) 的版本
BuildVersion: 当前版本的内部版本号
PSVersion: Windows PowerShell 版本号
WSManStackVersion: WS-Management 堆栈的版本号
PSCompatibleVersions: 与当前版本兼容的 Windows PowerShell 版本
SerializationVersion :序列化方法的版本
PSRemotingProtocolVersion:Windows PowerShell 远程管理协议的版本
$Pwd
包含一个路径对象,该对象表示当前目录的完整路径。
$Sender
包含生成此事件的对象。此变量只在事件注册命令的 Action 块内填充。
此变量的值也可在 Get-Event 返回的 PSEventArgs
(System.Management.Automation.PSEventArgs) 对象的 Sender 属性中找到。
$ShellID
包含当前 shell 的标识符。
$SourceArgs
包含表示正在被处理的事件的事件参数的对象。此变量只在事件注册命令的 Action
块内填充。此变量的值也可在 Get-Event 返回的 PSEventArgs
(System.Management.Automation.PSEventArgs) 对象的 SourceArgs 属性中找到。
$SourceEventArgs
包含一个对象,该对象表示从正在被处理的事件的 EventArgs 中派生出的
第一个事件参数。此变量只在事件注册命令的 Action 块内填充。
此变量的值也可在 Get-Event 返回的 PSEventArgs
(System.Management.Automation.PSEventArgs) 对象的 SourceArgs 属性中找到。
$This
在定义脚本属性或脚本方法的脚本块中,$This 变量引用要扩展的对象。
$True
包含 TRUE。可以在命令和脚本中使用此变量表示 TRUE。
PowerShell环境变量
传统的控制台一般没有象Powershell这么高级的变量系统。它们都是依赖于机器本身的环境变量,进行操作 。环境变量对于powershell显得很重要,因为它涵盖了许多操作系统的细节信息。此外,powershell中的变量只存在于powershell内部的会话中,一旦powershell关闭,这些变量就会自生自灭。但是如果环境变量被更新了,它会继续保存在操作系统中,即使其它程序也可以调用它。
1、读取特殊的环境变量
通过环境变量读取Windows操作系统的安装路径,和默认应用程序的安装路径。
通过$env:,这就提示powershell忽略基本的variable:驱动器,而是去环境变量env:驱动器中寻找变量。为了和其它变量保持一致,powershell环境变量也可以象其它变量那样使用。比如你可以把它插入到文本中。
2、查找环境变量
Powershell把所有环境变量的记录保存在env: 虚拟驱动中,因此可以列出所有环境变量 。一旦查出环境变量的名字就可以使用$env:name 访问了。
3、创建新的环境变量
创建新环境变量的方法和创建其它变量一样,只需要指定env:虚拟驱动器即可
4、删除和更新环境变量
在powershell删除和更新环境变量和常规变量一样。例如要删除环境变量中的 windir
可以更新环境变量$env:OS 为RedHat linux。
这样直接操作环境变量,会不会不安全?事实上很安全,因为$env:中的环境变量只是机器环境变量的一个副本,即使你更改了它,下一次重新打开时,又会恢复如初。(.NET方法更新环境变量除外)
PowerShell驱动器变量
Powershell中所有不是我们自己的定义的变量都属于驱动器变量(比如环境变量),它的前缀只是提供给我们一个可以访问信息的虚拟驱动器.。例如env:windir,象env:驱动器上的一个”文件”,我们通过$访问它,就会返回”文件”的内容。
1、直接访问文件路径
上述的例子有一个限制,就是${$home\a.bat}不能识别,原因是$后花括号中的路径必须是具体的路径,而不能带返回值。
解决方法:
因为反引号”`”放在$前,会把$解析成普通字符,解释器会继续去解析第二个$,发现$home,将其替换成了C:\Users\标标,此 Invoke-Expression的参数就变成了${C:\Users\标标\a.bat},继续执行这个表达式就可以了。
查看Powershell支持的驱动器,可以使用Get-PSDrive查看。
PSDrive中的大多都支持直接路径访问,例如可以通过函数路径,访问一个函数的具体实现。
2、特殊的变量:子表达式
由 $+圆括号+表达式 构成的变量属于子表达式变量,这样的变量会先计算表达式,然后把表达式的值返回。
例如 变量$(3+6),可以简写成(3+6),甚至可以简写成3+6。子表达式变量也可以嵌套在文本中,例如”result=$(3+6)”。在处理对象的属性时,会大量的用到表达式变量。
其实上面的代码可以简化为:
变量的作用域
Powershell所有的变量都有一个决定变量是否可用的作用域。Powershell支持四个作用域:全局、当前、私有和脚本。有了这些作用域就可以限制变量的可见性了,尤其是在函数和脚本中。
如果我们对变量不做特别的声明,Powershell解释器会自动处理和限制变量的作用域。将下面的内容命令保存着至test1.ps1
$windows = $env:windir
“Windows Folder: $windows”
调用脚本时,会分配一个变量$windows,在脚本调用结束后,这个变量被回收,脚本中的变量不会影响脚本外的变量,因为它们在不同的作用域中。powershell会针对每个函数和脚本给它们分配不同的作用域。
1、更改变量的可见性
你可以很容易的看到没有Powershell解释器自动限制可见性时会发生什么状况,同样是刚才的脚本,刚才的命令,只是在运行脚本时多加上一个点”.” 和一个空格:
在运行脚本时使用一个原点和空格,Powershell解释器就不会为脚本本身创建自己的变量作用域,它会共享当前控制台的作用域,这种不太灵活但却简单的方法,使用时一定要格外小心。
加强变量可见性限制的优点:清空初始化环境
例如,将下面文本保存为test.ps1,并调用没有任何问题:
New-Variable a -value 1 -option Constant
"Value: $a"
但是如果你通过圆点禁用作用域限制,调用test.ps1,就会有异常,因为一个常量不能被创建两次。
所以这种变量的作用域限制可以把变量的冲突降到最小。
2、设置单个变量的作用域
到目前为止,看到的变量作用域的改变都是全局的,能不能针对某个具体变量的作用域做一些个性化的设置。
$global
全局变量,在所有的作用域中有效,如果你在脚本或者函数中设置了全局变量,即使脚本和函数都运行结束,这个变量也任然有效。
$script
脚本变量,只会在脚本内部有效,包括脚本中的函数,一旦脚本运行结束,这个变量就会被回收。
$private
私有变量,只会在当前作用域有效,不能贯穿到其他作用域。
$local
默认变量,可以省略修饰符,在当前作用域有效,其它作用域只对它有只读权限。
打开Powershell控制台后,Powershell会自动生成一个新的全局作用域。如果增加了函数和脚本,或者特殊的定义,才会生成其它作用域。在当前控制台,只存在一个作用域,通过修饰符访问,其实访问的是同一个变量:
当调用一个已定义的函数,Powershell会生成第二个作用域,它可以对调用者的作用域中的变量执行读操作,但是不能执行写操作。
怎样把当前控制台中的变量保护起来,不让它在函数和脚本中被访问,Private修饰符就派上了用场。
变量的类型和强类型
变量可以自动存储任何Powershell能够识别的类型信息,可以通过$variable的GetType().Name查看和验证Powershell分配给变量的数据类型。
Powershell会给数据分配一个最佳的数据类型;如果一个整数超出了32位整数的上限([int32]::MaxValue),它就会分配一个64位整数的数据类型;如果碰到小数,会分配一个Double类型;如果是文本,Powershell会分配一个String类型;如果是日期或者时间,会被存储为一个Datetime对象。
这种类型自适应也称作“弱类型”,虽然使用起来方便,但是也会有一些限制,甚至危险。如果powershell选择了一个错误的类型付给变量,可能会引发一些奇怪的现象。例如有一个变量要存储的是即将拷贝文件的个数,可是在赋值时付了一个字符串,Powershell不会去做过多的判断,它会更新这个变量的类型,并且存储新的数据。所以一般专业的程序员或者脚本开发者更喜欢使用“强类型”,哪怕在赋值时类型不兼容的报错,他们也乐意接受。
喜欢使用强类型的另一个原因是:每一个数据类型都有属于自己的函数。例如DateTime,和XML,尽管这两种类型都可以用纯文本表示,但是使用强类型[DateTime]和[XML],对于数据操作起来更方便,这两个类型的方法可是很丰富奥!
指定类型定义变量
定义变量时可以在变量前的中括号中加入数据类型。例如定义一个Byte类型的变量,因为Byte的定义域为[0,255],一旦尝试使用一个不在定义域中的值赋给该变量就会显示一条错误信息。
使用固定类型的优点
手动地定义类型的一个重要原因是每个特殊的数据类型都有自己的特殊命令和特殊方法。比如把一个日期字符串赋给一个变量,Powershell不会自动把这个字符串转换成日期对象赋给一个变量,因为Powershell毕竟是机器,没有人那么智能。当你在赋值时指定DateTime类型时,你会发现几乎所有的.Net 中DateTime类型的方法在这里都得到支持。
Powershell处理Xml文档也很方便,
例如有如下LogoTest.xml
<logotest>
<extensions>
<e>.exe</e>
<e>.dll</e>
</extensions>
<files>
<f></f>
</files>
<dirs></dirs>
</logotest>
查询.exe 和 .dll结点
Powershell 默认支持的.NET类型如下。
[array],[bool],[byte],[char],[datetime],[decimal],[double],[guid],[hashtable],[int16],[int32],[int],[int64],[long],[nullable],[psobject],[regex],[sbyte].[scriptblock],[single],[float],[string],[switch],[timespan],[type],[uint16],[uint32],[uint64],[ XML ]
变量的幕后管理
在Powershell中创建一个变量,会在后台生成一个PSVariable对象,这个对象不仅包含变量的值,也包含变量的其它信息,例如”只写保护”这样的描述。
如果在Powershell中输出一个变量,只会输出这个变量的值。不能够显示它的其它信息,如果想查看一个变量的其它保留信息,就需要变量的基类PSVariable对象,这个可以通过Get-Variable命令得到,下面的例子演示如何查看一个变量的全部信息。
1、修改变量的选项设置
Powershell处理一个变量的PSVariable对象,主要是为了能够更新变量的选项设置。既可以使用命令Set-Variable,也可以在获取PSvariable对象后直接更改。比如更改一个变量的描述:
如果你不想多加一个临时变量$var来存储PSVariable,可以使用Powershell子表达式
2、激活变量的写保护
可以操作一个变量的选项设置 ,比如给一个变量加上写保护,需要将Option设置为“ReadOnly”
3、变量的选项
变量的选项是一个枚举值,包含:
“None”:默认设置
“ReadOnly”:变量只读,但是可以通过-Force 选项更新。
“Constant”:常量一旦声明,在当前控制台不能更新。
“Private”:只在当前作用域可见,不能贯穿到其它作用域
“AllScope”:全局,可以贯穿于任何作用域
4、变量的类型规范
变量的类型规范
每个变量的都有自己的类型,这个具体的类型存放在PsVariable对象的Attributes[System.Management.Automation.PSVariableAttributeCollection]属性,如果这个Attributes为空,可以给这个变量存放任何 类型的数据,Powershell会自己选择合适的类型。一旦这个Attributes属性确定下来,就不能随意存放数据了。例如给$var存放一个整数,属于弱类型,所以Attributes属性为空,这时还可以给它赋值一个字符串。但是如果给$var增加强类型,存放一个整数,再给它赋值一个其它类型,解释器会自动尝试转换,如果不能转换就会抛出异常。这时如果你非得更新$var变量的类型,可以使用 (Get-Variable var).Attributes.Clear(),清空Attributes,这样强类型就又转换成弱类型了。
5、验证和检查变量的内容
变量PSVariable对象的Attributes属性能够存储一些附件条件,例如限制变量的长度,这样在变量重新赋值时就会进行验证,下面演示如何限制一个字符串变量的长度为位于2-5之间。
常用的变量内容验证还有5种,分别为:
ValidateNotNullAttribute:限制变量不能为空
ValidateNotNullOrEmptyAttribute:限制变量不等为空,不能为空字符串,不能为空集合
ValidatePatternAttribute:限制变量要满足制定的正则表达式
ValidateRangeAttribute:限制变量的取值范围
ValidateSetAttribute:限制变量的取值集合
ValidateNotNullAttribute 例子
ValidateNotNullOrEmptyAttribute 例子,注意@()为一个空数组。