发现命令和脚本块

PowerShell发现命令

从用户的角度来看,在Powershell控制台上输入一条命令,然后直接回车执行,是一件简单的事情,事实上Powershell在后台做了很多事情,其中第一步,就是查看用户输入的命令是否可用,这个步骤也被称作自动化发现命令。使用Get-Command 命令可以查看当前作用域支持的所有命令。如果你想查看关于 LS 命令的信息,请把它传递给Get-Command。
PowerShell命令与脚本(11)——发现命令和脚本块_操作符
如果你想查看更加详细的信息可以使用:
PowerShell命令与脚本(11)——发现命令和脚本块_shell命令_02
在Powershell中有一个机制,就是函数永远处在最高的优先级。
看看下面的例子,通过函数可以重写ipconfig ,一旦删除该函数,原始的ipconfig才会重新登上历史的舞台:
PowerShell命令与脚本(11)——发现命令和脚本块_shell命令_03
 

PowerShell调用操作符

调用操作符“&”虽然简短,但是给我们执行Powershell命令提供了很大的方便。如果你之前将Powershell命令存储在了一个字符串中,或者一个变量中。此时,调用操作符就可以将字符串直接解释成命令并执行,如果在Powershell控制台中,你只须要输入即可。具体,如下:
PowerShell命令与脚本(11)——发现命令和脚本块_操作符_04
 
调用操作符只能接受单个命令
但是调用操作符不能接受全部的Powershell脚本或命令,只能接受单个的一条命令,例如使用:
PowerShell命令与脚本(11)——发现命令和脚本块_shell命令_05
为什么会这样呢?追根溯源,Powershell中的调用符,首先会使用get-command去发现命令是否可用,而get-command的确只支持单独的一条命令,不支持命令串或者脚本串。 调用操作符执行CommandInfo对象 调用操作符初始化时会将指定的文本传递给get-command,然后有get-command去检索命令,事实上,调用操作符甚至可以直接执行一个CommandInfo对象,绕过自身的内部get-command,例如:
PowerShell命令与脚本(11)——发现命令和脚本块_shell命令_06
 
通过命令名称唯一标识一条命令
但是可能存在别名,命令,函数的的名称一样,那Powershell会不会纠结到底执行哪个呢?当然不会,因为它们之间是有一个优先级的。从高到底,依次为:
  • Alias(1)
  • Function(2)
  • Filter(2)
  • Cmdlet(3)
  • Application(4)
  • ExternalScript(5)
  • Script (-)
下面举个例子:
PowerShell命令与脚本(11)——发现命令和脚本块_命令行_07
 

PowerShell使用语句块

脚本块是一种特殊的命令模式。一个脚本块可以包含许多的 Powershell命令和语句。它通常使用大括号定义。最小最短的脚本块,可能就是一对大括号,中间什么也没有。可以使用之前的调用操作符“&”执行脚本块:
PowerShell命令与脚本(11)——发现命令和脚本块_双引号_08
 
1、将命令行作为整体执行
可能你已经意识到,在Powershell中,调用操作符不但可以执行一条单独的命令,还可以执行”命令行”.最方便的方式就是讲你的命令行放在一个语句块中,作为整体。在之前的文章中说过,调用操作符只能执行一条命令,但是借助语句块的这把利器,可以让调用操作符执行,多条Powershell命令,例如:
PowerShell命令与脚本(11)——发现命令和脚本块_命令行_09
 
执行表达式
另外还有一条Powershell命令集,Invoke-Expression,这条命令的逻辑就是将一条字符串传递给调用操作符。例如:
PowerShell命令与脚本(11)——发现命令和脚本块_命令行_10
这里有一点需要注意,在传递给invoke-expression的字符串使用了单引号,单引号可以防止变量被替换。如果上面的命令使用了双引号,会先去解释$_.name,但是当前作用域中,$_.Name 为null,所以结果不是期望的。
 
管道中的foreach-object语句块
管道中的foreach-object本身后面也会带语句块,针对数组中的每一个元素分别传递给语句块处理。 例如:
Get-Process | ForEach-Object { $_.name }
条件和循环中的语句块
 
条件和循环中的语句块
在条件语句中,如果条件满足,做一件事,条件不满足做另外一件事,这一件事或者另外一件事本身应当是一个整体,尽管本身可能包含了许多命令和语句。所以会把它们放在一个语句块中。
在循环语句中,如果条件满足循环做一件事,这一件事本身,也是一个整体。 这里就不举例了。
 
函数本身是一个已命名的语句块
为什么把函数和语句块归结在一起呢?请看下面的例子。
PowerShell命令与脚本(11)——发现命令和脚本块_双引号_11
 
2、构建语句块
既然函数只是被命令的语句块,那是不是也可以通过语句块就能实现函数的特性呢?接下来就验证一下吧。
传递参数给语句块
PowerShell命令与脚本(11)——发现命令和脚本块_命令行_12
定义和传递参数一次性完成,有点匿名函数的味道。
 
Begin, Process, End 管道语句块
之前讲过定义函数也可以按照Begin, Process, End的结构,这样尤其可以实时处理管道数据。那能不能也直接通过语句块定义呢?
PowerShell命令与脚本(11)——发现命令和脚本块_shell命令_13
 
验证变量
函数中的所有变量都是内置的,属于函数定义域。除非你指定给一个全局变量赋值。首先通过函数实现:
PowerShell命令与脚本(11)——发现命令和脚本块_命令行_14
那语句块也支持吗?例如:
PowerShell命令与脚本(11)——发现命令和脚本块_操作符_15
 

PowerShell执行上下文

Powershell 提供了一个非常特别的自动化变量,$ExecutionContext。这个变量可能会很少碰到,但是理解它的机制,有助于我们理解Powershell执行命令和脚本的内部机制。这个对象主要包含两个属性:InvokeCommand 和 SessionState.
PowerShell命令与脚本(11)——发现命令和脚本块_操作符_16
 
1、InvokeCommand
到目前为止,我们在Powershell控制台中遇到三个比较特殊的字符,字符串标识双引号,调用操作符 &,和脚本块标识花括号。
 
 
特殊字符
定义
内部方法
处理字符串中的变量
ExpandString()
&
执行命令集
InvokeScript()
{}
创建一个新的代码块
NewScriptBlock()
处理变量
每当你在Powershell的字符串中放置一个变量,Powershell解释器会自动处理该变量,并将变量替换成变量本身的值或者内容。
PowerShell命令与脚本(11)——发现命令和脚本块_双引号_17
既然双引号的机制是ExpandString()方法,那么也可以自己调用该方法
PowerShell命令与脚本(11)——发现命令和脚本块_命令行_18
 
创建脚本块
如果将Powershell代码放置在花括号中,这样既可以使用调用操作符&执行脚本,也可以将脚本块赋值给一个函数,因为之前的文章中说过,函数是一个命令的脚本块.
PowerShell命令与脚本(11)——发现命令和脚本块_双引号_19
 
执行命令行
输入的命令行可以通过InvokeScript()脚本执行,也可以使用&执行,也可以使用Invoke-Expression命令执行
PowerShell命令与脚本(11)——发现命令和脚本块_命令行_20
 
2、SessionState
SessionState是一个用来表现Powershell环境的对象,你同样可以通过自动化变量$ExecutionContext访问这些信息.
PowerShell命令与脚本(11)——发现命令和脚本块_双引号_21
PSVariable,可以取出和更新Powershell中所有的变量.
PowerShell命令与脚本(11)——发现命令和脚本块_双引号_22
 
管理驱动器
查看当前驱动器信息
PowerShell命令与脚本(11)——发现命令和脚本块_命令行_23
查看所有驱动器信息
$ExecutionContext.SessionState.Drive.GetAll() | ft
PowerShell命令与脚本(11)——发现命令和脚本块_操作符_24
如果你的只想关注特定的驱动器,可以使用下面的方法:
PowerShell命令与脚本(11)——发现命令和脚本块_操作符_25
 
路径操作
SessionState的Path包含几个特殊的方法,基本可以覆盖各种常用的路径操作了
方法
描述
对应的命令
CurrentLocation
当前路径
Get-Location
PopLocation()
获取存储的路径
Pop-Location
PushCurrentLocation()
存储路径
Push-Location
SetLocation()
定位路径
Set-Location
GetResolvedPSPathFromPSPath()
相对路径转换成绝对路径
Resolve-Location