设为首页 收藏本站
查看: 997|回复: 0

25. PowerShell -- 命令发现和脚本块

[复制链接]

尚未签到

发表于 2018-9-2 12:17:26 | 显示全部楼层 |阅读模式

  •   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.1

  •   PowerShell之调用操作符
  调用操作符“&”虽然简短,但是给我们执行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
  

  
映像名称                       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语句块
  管道中的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 管道语句块
  之前讲过定义函数也可以按照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
InvokeCommand
  到目前为止,我们在Powershell控制台中遇到三个比较特殊的字符,字符串标识双引号,调用操作符 &,和脚本块标识花括号。
特殊字符定义内部方法“处理字符串中的变量ExpandString()&执行命令集InvokeScript(){}创建一个新的代码块NewScriptBlock()处理变量
  每当你在Powershell的字符串中放置一个变量,Powershell解释器会自动处理该变量,并将变量替换成变量本身的值或者内容。
1234$site = '飞苔博客'# 双引号中的变量会被自动解析成变量的值:$text = "我的个人网站 $site"$text
  输出:
  我的个人网站 飞苔博客
  既然双引号的机制是ExpandString()方法,那么也可以自己调用该方法
123456$site = '飞苔博客'# 双引号中的变量会被自动解析成变量的值:$text = '我的个人网站 $site'$text#通过ExpandString()自动处理字符串中的变量$executioncontext.InvokeCommand.ExpandString($text)
  输出:
  我的个人网站 $site
  我的个人网站 飞苔博客
创建脚本块
  如果将Powershell代码放置在花括号中,这样既可以使用调用操作符&执行脚本,也可以将脚本块赋值给一个函数,因为之前的文章中说过,函数是一个命令的脚本块.
1234567891011121314# 创建新的脚本块$block = {$write=Get-Process WindowsLiveWriter"$($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)
  输入的命令行可以通过InvokeScript()脚本执行,也可以使用&执行,也可以使用Invoke-Expression命令执行
1234$cmd='3*3*3.14'& { 3*3*3.14}$executioncontext.InvokeCommand.InvokeScript($cmd)Invoke-Expression $cmd
  输出:
  28.26
  28.26
  28.26
SessionState
  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.CommandInvocationIntrinsics
  PSVariable,可以取出和更新Powershell中所有的变量.
12345678$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-LocationPopLocation()获取存储的路径Pop-LocationPushCurrentLocation()存储路径Push-LocationSetLocation()定位路径Set-LocationGetResolvedPSPathFromPSPath()相对路径转换成绝对路径Resolve-Location


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-561559-1-1.html 上篇帖子: 24. PowerShell -- 使用特殊文本命令(-contains字符串比较,-like 匹配字符) 下篇帖子: powershell更改用户信息
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表