标签:powersell
PowerShell之发现命令
从用户的角度来看,在Powershell控制台上输入一条命令,然后直接回车执行,是一件简单的事情,事实上Powershell在后台做了很多事情,其中第一步,就是查看用户输入的命令是否可用,这个步骤也被称作自动化发现命令。使用Get-Command 命令可以查看当前作用域支持的所有命令。如果你想查看关于 LS 命令的信息,请把它传递给Get-Command。
PS C:> Get-command LS CommandType Name Definition ----------- ---- ---------- Alias ls Get-ChildItem
如果你想查看更加详细的信息可以使用:
HelpUri             : http://go.microsoft.com/fwlink/?LinkID=113308
ResolvedCommandName : Get-ChildItem
ReferencedCommand   : Get-ChildItem
ResolvedCommand     : Get-ChildItem
Definition          : Get-ChildItem
Options             : AllScope
Description         :
OutputType          : {System.IO.FileInfo, System.IO.DirectoryInfo, System.String}
Name                : ls
CommandType         : Alias
Visibility          : Public
ModuleName          :
Module              :
Parameters          : {[Path, System.Management.Automation.ParameterMetadata], [Literal
                       [Include, System.Management.Automation.ParameterMetadata]...}
ParameterSets如果你想查看命令IPConfig的命令信息,可以使用:
PS C:> get-command ipconfig CommandType Name Definition ----------- ---- ---------- Application ipconfig.exe C:windowsSYSTEM32ipconfig.exe 事实上,Get-Command 返回的是一个对象CommandInfo,ApplicationInfo,FunctionInfo,或者CmdletInfo; PS C:> $info = Get-Command ping PS C:> $info.GetType().fullname System.Management.Automation.ApplicationInfo PS C:> $info = Get-Command ls PS C:> $info.GetType().fullname System.Management.Automation.AliasInfo PS C:> $info = Get-Command Get-Command PS C:> $info.GetType().fullname System.Management.Automation.CmdletInfo PS C:> $info=Get-Command more | select -First 1 PS C:> $info.GetType().fullname System.Management.Automation.FunctionInfo
如果一条命令可能指向两个实体,get-command也会返回,例如more。
PS C:> Get-Command more CommandType Name Definition ----------- ---- ---------- Function more param([string[]]$paths)... Application more.com C:windowsSYSTEM32more.com
这两条命令,前者是Powershell的自定义函数,后者是扩展的Application命令。细心的读者可能会提问,这两个会不会发生冲突。当然不会,默认会调用第一个,是不是仅仅因为它排在第一个,不是,而是在Powershell中有一个机制,就是函数永远处在最高的优先级。不信,看看下面的例子,通过函数可以重写ipconfig ,一旦删除该函数,原始的ipconfig才会重新登上历史的舞台:
PS C:> function Get-Command () {}
PS C:> Get-Command
PS C:> del Function:Get-Command
PS C:> function ipconfig(){}
PS C:> ipconfig
PS C:> del Function:ipconfig
PS C:> ipconfnig
PS C:> ipconfig.exe
Windows IP 配置
无线局域网适配器 无线网络连接 3:
   媒体状态  . . . . . . . . . . . . : 媒体已断开
   连接特定的 DNS 后缀 . . . . . . . :
无线局域网适配器 无线网络连接 2:
   媒体状态  . . . . . . . . . . . . : 媒体已断开
   连接特定的 DNS 后缀 . . . . . . . :
无线局域网适配器 无线网络连接:
   连接特定的 DNS 后缀 . . . . . . . :
   本地链接 IPv6 地址. . . . . . . . : fe80::9c4:7e81:82a2:1a3e%15
   IPv4 地址 . . . . . . . . . . . . : 192.168.1.100
   子网掩码  . . . . . . . . . . . . : 255.255.255.0
   默认网关. . . . . . . . . . . . . : 192.168.1.1PowerShell之调用操作符
调用操作符“&”虽然简短,但是给我们执行Powershell命令提供了很大的方便。如果你之前将Powershell命令存储在了一个字符串中,或者一个变量中。此时,调用操作符就可以将字符串直接解释成命令并执行,如果在Powershell控制台中,你只须要输入即可。具体,如下:
#将命令存储在变量中: $command = "Dir $env:windir" # 如果直接输出变量,字符串原样输出。 $command #Dir #如果使用调用操作符"&" & $command 目录: E: Mode LastWriteTime Length Name ---- ------------- ------ ---- d---- 2012/5/9 0:42 Blog d---- 2012/5/23 21:45 DooMLoRD_v3_ROOT-zergRush-busybox- su d---- 2012/6/1 20:21 Haitch-TFS d---- 2012/3/25 15:32 KillProcess
但是调用操作符不能接受全部的Powershell脚本或命令,只能接受单个的一条命令,例如使用:
$command = "Dir $env:windir" & $command 就会报错 无法将“Dir C:windows”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后重试。 所在位置 E:MyScript.ps1:6 字符: 2 + & <<<< $command + CategoryInfo : ObjectNotFound: (Dir C:windows:String) [], Comm andNotFoundException + FullyQualifiedErrorId : CommandNotFoundException $command = get-command dir & $command = $env:windir
为什么会这样呢?追根溯源,Powershell中的调用符,首先会使用get-command去发现命令是否可用,而get-command的确只支持单独的一条命令,不支持命令串或者脚本串。 调用操作符执行CommandInfo对象 调用操作符初始化时会将指定的文本传递给get-command,然后有get-command去检索命令,事实上,调用操作符甚至可以直接执行一个CommandInfo对象,绕过自身的内部get-command,例如:
PS E:> $command=Get-Command tasklist PS E:> $command CommandType Name ----------- ---- Application tasklist.exe PS E:> & $command 映像名称 PID 会话名 会话# 内存使用 ========================= ======== ================ =========== ============ System Idle Process 0 Services 0 24 K System 4 Services 0 560 K smss.exe 356 Services 0 756 K csrss.exe 564 Services 0 3,744 K csrss.exe 680 Console 1 71,512 K wininit.exe 688 Services 0 2,904 K services.exe 740 Services 0 8,552 K lsass.exe 764 Services 0 10,676 K lsm.exe 776 Services 0 3,240 K
但是可能存在别名,命令,函数的的名称一样,那Powershell会不会纠结到底执行哪个呢?当然不会,因为它们之间是有一个优先级的。从高到底,依次为:
Alias(1)
Function(2)
Filter(2)
Cmdlet(3)
Application(4)
ExternalScript(5)
Script (-)
下面举个例子:
PS E:> function Ping(){"我是Ping函数"}
PS E:> Set-Alias -Name Ping -Value echo
CommandType Name     Definition
----------- ----     ----------
Alias       Ping     echo
Function    Ping     param()...
Application PING.EXE C:windowsSYSTEM32PING.EXE
PS E:> ping "测试我的Ping,估计执行的别名echo"
测试我的Ping,估计执行的别名echo
PS E:> del Alias:Ping
PS E:> ping ; #别名已经被删除,估计执行的是函数PING
我是Ping函数
PS E:> del Function:Ping
PS E:> ping baidu.com ; #函数已经被删除,估计执行的是函数ping 程序
正在 Ping baidu.com [220.181.111.85] 具有 32 字节的数据:
请求超时。
请求超时。
请求超时。
请求超时。
220.181.111.85 的 Ping 统计信息:
    数据包: 已发送 = 4,已接收 = 0,丢失 = 4 (100% 丢失),那怎样突破优先级的限制执行指定的命令呢?方法都是大同小异,通过特定信息过滤到指定的CommandInfo对象,然后直接使用我们本篇的调用操作符。例如当存在如下的命令Ping命令
CommandType     Name
-----------     ----
Alias           Ping
Function        Ping
Application     PING.EXE
我想调用第三个,可以使用:
PS E:> $command=Get-Command -Name ping | where {$_.CommandType -eq "Application" }
PS E:> & $command
用法: ping [-t] [-a] [-n count] [-l size] [-f] [-i TTL] [-v TOS]
           [-r count] [-s count] [[-j host-list] | [-k host-list]]
           [-w timeout] [-R] [-S srcaddr] [-4] [-6] target_name
选项:
    -t             Ping 指定的主机,直到停止。
                   若要查看统计信息并继续操作 - 请键入 Control-Break;
                   若要停止 - 请键入 Control-C。
    -a             将地址解析成主机名。
    -n count       要发送的回显请求数。
    -l size        发送缓冲区大小。
    -f             在数据包中设置“不分段”标志(仅适用于 IPv4)。
    -i TTL         生存时间。
    -v TOS         服务类型(仅适用于 IPv4。该设置已不赞成使用,且
                   对 IP 标头中的服务字段类型没有任何影响)。
    -r count       记录计数跃点的路由(仅适用于 IPv4)。
    -s count       计数跃点的时间戳(仅适用于 IPv4)。
    -j host-list   与主机列表一起的松散源路由(仅适用于 IPv4)。
    -k host-list   与主机列表一起的严格源路由(仅适用于 IPv4)。
    -w timeout     等待每次回复的超时时间(毫秒)。
    -R             同样使用路由标头测试反向路由(仅适用于 IPv6)。
    -S srcaddr     要使用的源地址。
    -4             强制使用 IPv4。
    -6             强制使用 IPv6。
#或者& (Get-Command -Name ping)[2]PowerShell之使用语句块
脚本块是一种特殊的命令模式。一个脚本块可以包含许多的 Powershell命令和语句。它通常使用大括号定义。最小最短的脚本块,可能就是一对大括号,中间什么也没有。可以使用之前的调用操作符“&”执行脚本块:
PS E:> & {"当前时间:" + (get-date) }
当前时间:08/08/2012 22:30:24
将命令行作为整体执行
PS E:> & {$files=ls;Write-Host "文件数:" $files.Count }
文件数: 29
另外还有一条Powershell命令集,Invoke-Expression,这条命令的逻辑就是将一条字符串传递给调用操作符。例如:
PS E:> Invoke-Expression ‘Get-Process | Where-Object { $_.Name -like "e*"}‘
Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
    332      29    12280      24264   154     1.40   3236 egui
    386      32    78624      85508   183            1884 ekrn
    284      22     8980      17048    99            1920 EvtEng
   1000      89    55520      83280   355    23.24   2848 explorer这里有一点需要注意,在传递给invoke-expression的字符串使用了单引号,单引号可以防止变量被替换。如果上面的命令使用了双引号,会先去解释$_.name,但是当前作用域中,$_.Name 为null,所以结果不是期望的。
管道中的foreach-object本身后面也会带语句块,针对数组中的每一个元素分别传递给语句块处理。 例如:
 Get-Process | ForEach-Object { $_.name }在条件语句中,如果条件满足,做一件事,条件不满足做另外一件事,这一件事或者另外一件事本身应当是一个整体,尽管本身可能包含了许多命令和语句。所以会把它们放在一个语句块中。
在循环语句中,如果条件满足循环做一件事,这一件事本身,也是一个整体。 这里就不举例了。
为什么把函数和语句块归结在一起呢?请看下面的例子。
#定义一个函数
Function SayHello([string]$people="everyone")
{
	write-host "Hello, $people ”
}
#通过函数调用
SayHello "Mosser"
Hello, Mosser
#通过语句块调用
$scriptblocks = {
param([string]$people="everyone")
write-host "Hello, $people ”
}
& $scriptblocks
Hello, everyone既然函数只是被命令的语句块,那是不是也可以通过语句块就能实现函数的特性呢?接下来就验证一下吧。
在函数中可以传递参数:
Function SayHello([string]$people="everyone")
{
	write-host "Hello, $people ”
}能否在语句块中也传递参数?
& { param($people="everyone") write-host "Hello, $people ” } "Mosser"
Hello, Mosser定义和传递参数一次性完成,有点匿名函数的味道。
之前讲过定义函数也可以按照Begin, Process, End的结构,这样尤其可以实时处理管道数据。那能不能也直接通过语句块定义呢?
get-process | select -last 5 | & {
begin {
"开始准备环境"
}
process
{
 $_.Name
}
end {
"开始清理环境"
}
}
#输出结果为:
开始准备环境
wlcommsvc
WLIDSVC
WLIDSVCM
WmiPrvSE
XDict
开始清理环境函数中的所有变量都是内置的,属于函数定义域。除非你指定给一个全局变量赋值。首先通过函数实现:
function Test
{
$value1 = 10
$global:value2 = 20
}
Test
$value1  结果为空:   
$value2   结果为空:
 20那语句块也支持吗?例如:
& { $value1 = 10; $global:value2 = 20 }
$value1  结果为空:   
                            
  
$value2   结果为空:
20
PowerShell之执行上下文
Powershell 提供了一个非常特别的自动化变量,$ExecutionContext。这个变量可能会很少碰到,但是理解它的机制,有助于我们理解Powershell执行命令和脚本的内部机制。这个对象主要包含两个属性:InvokeCommand 和 SessionState.
PS E:> $ExecutionContext Host : System.Management.Automation.Internal.Host.InternalHost Events : System.Management.Automation.PSLocalEventManager InvokeProvider : System.Management.Automation.ProviderIntrinsics SessionState : System.Management.Automation.SessionState InvokeCommand : System.Management.Automation.CommandInvocationIntrinsics
到目前为止,我们在Powershell控制台中遇到三个比较特殊的字符,字符串标识双引号,调用操作符 &,和脚本块标识花括号。
| 特殊字符 | 定义 | 内部方法 | 
| “ | 处理字符串中的变量 | ExpandString() | 
| & | 执行命令集 | InvokeScript() | 
| {} | 创建一个新的代码块 | NewScriptBlock() | 
每当你在Powershell的字符串中放置一个变量,Powershell解释器会自动处理该变量,并将变量替换成变量本身的值或者内容。
| 1 2 3 4 | $site= ‘飞苔博客‘# 双引号中的变量会被自动解析成变量的值:$text= "我的个人网站 $site"$text | 
输出:
我的个人网站 飞苔博客
既然双引号的机制是ExpandString()方法,那么也可以自己调用该方法
| 1 2 3 4 5 6 | $site= ‘飞苔博客‘# 双引号中的变量会被自动解析成变量的值:$text= ‘我的个人网站 $site‘$text#通过ExpandString()自动处理字符串中的变量$executioncontext.InvokeCommand.ExpandString($text) | 
输出:
我的个人网站 $site
我的个人网站 飞苔博客
如果将Powershell代码放置在花括号中,这样既可以使用调用操作符&执行脚本,也可以将脚本块赋值给一个函数,因为之前的文章中说过,函数是一个命令的脚本块.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # 创建新的脚本块$block= {$write=Get-ProcessWindowsLiveWriter"$($write.Name) 占用内存: $($write.WorkingSet/1mb) MB"}$block.GetType().Name& $block# 使用NewScriptBlock方法创建脚本块:$blockStr=‘$write=Get-Process WindowsLiveWriter"$($write.Name) 占用内存: $($write.WorkingSet/1mb) MB"‘$block= $executioncontext.InvokeCommand.NewScriptBlock($blockStr)$block.GetType().Name& $block | 
输出:
ScriptBlock
WindowsLiveWriter 占用内存: 150.734375 MB
ScriptBlock
WindowsLiveWriter 占用内存: 150.734375 MB
输入的命令行可以通过InvokeScript()脚本执行,也可以使用&执行,也可以使用Invoke-Expression命令执行
| 1 2 3 4 | $cmd=‘3*3*3.14‘& { 3*3*3.14}$executioncontext.InvokeCommand.InvokeScript($cmd)Invoke-Expression$cmd | 
输出:
28.26
28.26
28.26
SessionState是一个用来表现Powershell环境的对象,你同样可以通过自动化变量$ExecutionContext访问这些信息.
PS E:> $executioncontext.SessionState | Format-List *
Drive                         : System.Management.Automation.DriveManagementIntrinsics
Provider                      : System.Management.Automation.CmdletProviderManagementIntrinsics
Path                          : System.Management.Automation.PathIntrinsics
PSVariable                    : System.Management.Automation.PSVariableIntrinsics
LanguageMode                  : FullLanguage
UseFullLanguageModeInDebugger : False
Scripts                       : {*}
Applications                  : {*}
Module                        :
InvokeProvider                : System.Management.Automation.ProviderIntrinsics
InvokeCommand                 : System.Management.Automation.CommandInvocationIntrinsicsPSVariable,可以取出和更新Powershell中所有的变量.
| 1 2 3 4 5 6 7 8 | $value= "Test"# Retrieve variable contents:$executioncontext.SessionState.PSVariable.GetValue("value")Test# Modify variable contents:$executioncontext.SessionState.PSVariable.Set("value", 100)$value100 | 
输出:
Powershell博客 飞苔博客
Powershell博客 网站http://www.mossfly.com
查看当前驱动器信息
PS E:> $executioncontext.SessionState.Drive.Current Name Used (GB) Free (GB) Provider Root CurrentLocation ---- --------- --------- -------- ---- --------------- E 1.67 78.33 FileSystem E:
查看所有驱动器信息
PS E:> $executioncontext.SessionState.Drive.GetAll() | ft - Name Used (GB) Free (GB) Provider Root ---- --------- --------- -------- ---- WSMan WSMan Alias Alias Env Environment C 44.48 35.52 FileSystem C: D 18.69 52.16 FileSystem D: E 1.67 78.33 FileSystem E: G 52.57 118.55 FileSystem G: I 27.31 21.52 FileSystem I: Function Function HKLM Registry HKEY_LOCAL_MACHINE HKCU Registry HKEY_CURRENT_USER Variable Variable cert Certificate F FileSystem F: H .67 FileSystem H:
如果你的只想关注特定的驱动器,可以使用下面的方法:
PS E:> $executioncontext.SessionState.Drive.GetAllForProvider("FileSystem")
Name Used (GB) Free (GB) Provider   Root CurrentLocation
---- --------- --------- --------   ---- ---------------
C        44.48     35.52 FileSystem C:    Usersbaozhen
D        18.69     52.16 FileSystem D:
E         1.67     78.33 FileSystem E:
G        52.57    118.55 FileSystem G:
I        27.31     21.52 FileSystem I:
F                        FileSystem F:
H          .67           FileSystem H:SessionState的Path包含几个特殊的方法,基本可以覆盖各种常用的路径操作了
| 方法 | 描述 | 对应的命令 | 
| CurrentLocation | 当前路径 | Get-Location | 
| PopLocation() | 获取存储的路径 | Pop-Location | 
| PushCurrentLocation() | 存储路径 | Push-Location | 
| SetLocation() | 定位路径 | Set-Location | 
| GetResolvedPSPathFromPSPath() | 相对路径转换成绝对路径 | Resolve-Location | 
本文出自 “Ricky's Blog” 博客,请务必保留此出处http://57388.blog.51cto.com/47388/1643790
标签:powersell
原文地址:http://57388.blog.51cto.com/47388/1643790