• PowerShell笔记


    本系列是一个重新学习PowerShell的笔记,内容引用自PowerShell中文博客

    发现命令

    从用户的角度来看,在Powershell控制台上输入一条命令,然后直接回车执行,是一件简单的事情,事实上Powershell在后台做了很多事情,其中第一步,就是查看用户输入的命令是否可用,这个步骤也被称作自动化发现命令。使用Get-Command 命令可以查看当前作用域支持的所有命令。如果你想查看关于 LS 命令的信息,请把它传递给Get-Command

    PS C:PowerShell> Get-Command Ls                                                                                        
    CommandType     Name                                               Version    Source
    -----------     ----                                               -------    ------
    Alias           ls -> Get-ChildItem
    
    #查询详细信息
    PS C:PowerShell> Get-Command Ls |Format-List *                                                                         
    
    HelpUri             : https://go.microsoft.com/fwlink/?LinkID=113308
    ResolvedCommandName : Get-ChildItem
    DisplayName         : ls -> Get-ChildItem
    ReferencedCommand   : Get-ChildItem
    ResolvedCommand     : Get-ChildItem
    Definition          : Get-ChildItem
    Options             : AllScope
    Description         :
    OutputType          : {System.IO.FileInfo, System.IO.DirectoryInfo}
    Name                : ls
    CommandType         : Alias
    Source              :
    Version             :
    Visibility          : Public
    ModuleName          :
    Module              :
    RemotingCapability  : PowerShell
    Parameters          : {[Path, System.Management.Automation.ParameterMetadata], [LiteralPath, System.Management.Automati
                          on.ParameterMetadata], [Filter, System.Management.Automation.ParameterMetadata], [Include, System
                          .Management.Automation.ParameterMetadata]...}
    ParameterSets       :
    
    

    如果你想查看命令IPConfig的命令信息,可以使用:

    PS C:PowerShell> Get-Command ipconfig | Format-List *                                                                  
    
    HelpUri            :
    FileVersionInfo    : File:             C:WINDOWSsystem32ipconfig.exe
                         InternalName:     ipconfig.exe
                         OriginalFilename: ipconfig.exe.mui
                         FileVersion:      10.0.18362.1 (WinBuild.160101.0800)
                         FileDescription:  IP Configuration Utility
                         Product:          Microsoft® Windows® Operating System
                         ProductVersion:   10.0.18362.1
                         Debug:            False
                         Patched:          False
                         PreRelease:       False
                         PrivateBuild:     False
                         SpecialBuild:     False
                         Language:         English (United States)
    
    Path               : C:WINDOWSsystem32ipconfig.exe
    Extension          : .exe
    Definition         : C:WINDOWSsystem32ipconfig.exe
    Source             : C:WINDOWSsystem32ipconfig.exe
    Version            : 10.0.18362.1
    Visibility         : Public
    OutputType         : {System.String}
    Name               : ipconfig.exe
    CommandType        : Application
    ModuleName         :
    Module             :
    RemotingCapability : PowerShell
    Parameters         :
    ParameterSets      :
    
    
    

    事实上,Get-Command 返回的是一个对象CommandInfo,ApplicationInfo,FunctionInfo,或者CmdletInfo;

     $info = Get-Command ping
     $info.GetType().FullName
     $info = Get-Command ls
     $info.GetType().FullName
     $info = Get-Command Get-Command
     $info.GetType().FullName
     $info=Get-Command more | Select-Object -First 1
     $info.GetType().FullName
    
    PS C:PowerShell> test.ps1                                                                            System.Management.Automation.ApplicationInfo
    System.Management.Automation.AliasInfo
    System.Management.Automation.CmdletInfo
    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才会重新登上历史的舞台:

    
    function ipconfig() {"自定义Ipconfig Function"}
    ipconfig
    del Function:ipconfig
    ipconfig
    
    PS C:PowerShell> test.ps1                                                                            自定义Ipconfig Function
    
    Windows IP Configuration
    
    Ethernet adapter Ethernet:
    
       Media State . . . . . . . . . . . : Media disconnected
       Connection-specific DNS Suffix  . :
    .
    .
    .
    

    调用操作符

    调用操作符“&”虽然简短,但是给我们执行Powershell命令提供了很大的方便。如果你之前将Powershell命令存储在了一个字符串中,或者一个变量中。此时,调用操作符就可以将字符串直接解释成命令并执行,如果在Powershell控制台中,你只须要输入即可。具体,如下:

    PS C:PowerShell> $command = "ls"                                                                                       PS C:PowerShell> $command                                                                                              ls
    PS C:PowerShell> &$command                                                                                             
    
        Directory: C:PowerShell
    
    
    Mode                LastWriteTime         Length Name
    ----                -------------         ------ ----
    -a----        2021/9/16     13:55            812 Error.txt
    -a----        2021/9/15     15:45            397 pipeline.ps1
    -a----        2021/9/15     10:46              0 test.exe
    -a----        2021/9/15     14:58             36 test.ps1
    -a----        2021/9/14     13:51             58 test.txt
    

    调用操作符只能接受单个命令
    调用操作符不能接受全部的Powershell脚本或命令,只能接受单个的一条命令,例如使用:

    PS C:PowerShell> $command = "dir $env:windir"                                                                          PS C:PowerShell> $command                                                                                              dir C:WINDOWS
    PS C:PowerShell> &$command                                                                                             & : The term 'dir C:WINDOWS' is not recognized as the name of a cmdlet, function, script file, or operable program. Ch
    eck the spelling of the name, or if a path was included, verify that the path is correct and try again.
    At line:1 char:2
    + &$command
    +  ~~~~~~~~
        + CategoryInfo          : ObjectNotFound: (dir C:WINDOWS:String) [], CommandNotFoundException
        + FullyQualifiedErrorId : CommandNotFoundException
    

    为什么会这样呢?
    追根溯源,Powershell中的调用符,首先会使用get-command去发现命令是否可用,而get-command的确只支持单独的一条命令,不支持命令串或者脚本串。
    调用操作符执行CommandInfo对象调用操作符初始化时会将指定的文本传递给get-command,然后有get-command去检索命令,事实上,调用操作符甚至可以直接执行一个CommandInfo对象,绕过自身的内部get-command,例如:

    PS C:PowerShell> $command=Get-Command tasklist                                                                         PS C:PowerShell> $command                                                                                              
    CommandType     Name                                               Version    Source
    -----------     ----                                               -------    ------
    Application     tasklist.exe                                       10.0.18... C:WINDOWSsystem32	asklist.exe
    
    

    通过命令名称唯一标识一条命令

    但是可能存在别名,命令,函数的的名称一样,那Powershell会不会纠结到底执行哪个呢?当然不会,因为它们之间是有一个优先级的。从高到底,依次为:
    Alias(1)
    Function(2)
    Filter(2)
    Cmdlet(3)
    Application(4)
    ExternalScript(5)
    Script (-)

    function Test() {"我是个别名"}
    function Ping() { "我是Ping函数" }
    Set-Alias -Name Ping -Value Test
    ping
    del Alias:Ping
    ping
    del Function:Ping
    ping baidu.com 
    
    PS C:PowerShell> test.ps1
    我是个别名
    我是Ping函数
    
    Pinging baidu.com [220.181.38.251] with 32 bytes of data:
    Control-C
    

    语句块

    脚本块是一种特殊的命令模式。一个脚本块可以包含许多的 Powershell命令和语句。它通常使用大括号定义。最小最短的脚本块,可能就是一对大括号,中间什么也没有。可以使用之前的调用操作符“&”执行脚本块:

    PS C:PowerShell>  & {"当前时间:" + (get-date) }
    当前时间:09/16/2021 16:54:21
    

    将命令行作为整体执行

    可能你已经意识到,在Powershell中调用操作符不但可以执行一条单独的命令,还可以执行”命令行”.最方便的方式就是将你的命令行放在一个语句块中,作为整体。
    在前文中说过,调用操作符只能执行一条命令,但是借助语句块的这把利器,可以让调用操作符执行,多条Powershell命令,例如:

    PS C:PowerShell> & {$files=ls;Write-Host "文件数:" $files.Count }
    文件数: 5
    

    执行表达式

    另外还有一条Powershell命令集,Invoke-Expression,这条命令的逻辑就是将一条字符串传递给调用操作符。例如:

    PS C:PowerShell> Invoke-Expression 'Get-Process | Where-Object { $_.Name -like "Micro*"}'                              
    Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  SI ProcessName
    -------  ------    -----      -----     ------     --  -- -----------
        967      61    40680       5380       3.64  14412   1 Microsoft.Notes
        541      29    43884      29996       7.59  16712   1 Microsoft.ServiceHub.Controller
        406      27    25784      14460              5712   0 MicrosoftSearchInBing
        374      51    39812      22020       4.44  20932   1 MicrosoftSqlToolsServiceLayer
    

    这里有一点需要注意,在传递给invoke-expression的字符串使用了单引号,单引号可以防止变量被替换。如果上面的命令使用了双引号,会先去解释$_.name,但是当前作用域中,$_.Name$null,所以结果不是期望的。

    函数本身是一个已命名的语句块

    为什么把函数和语句块归结在一起呢?请看下面的例子。

    Function SayHello([string]$people = "everyone") {
    	Write-Host "Hello, $people ”
    }
    #赋值Funciton引用
    $func = $Function:SayHello
    Write-Host "--------------------"
    #查看语句
    $func
    Write-Host "--------------------"
    #通过操作符调用
    &$func "Hua Hua"
    Write-Host "--------------------"
    #创建语句块
    $func = { param([string]$people = "everyone") write-host "Hello, $people ” }
    Write-Host "--------------------"
    #查看语句块
    $func
    Write-Host "--------------------"
    #执行语句块
    &$func
    #向语句块传递参数
    Write-Host "--------------------"
    &$func "Hua Hua"
    #直接向语句块传递参数
    & { param([string]$people = "everyone") write-host "Hello, $people ” } "Hua Hua"
    
    PS C:PowerShell> test.ps1                                                                            --------------------
    param([string]$people = "everyone")
    
            Write-Host "Hello, $people ”
    
    --------------------
    Hello, Hua Hua
    --------------------
    --------------------
     param([string]$people = "everyone") write-host "Hello, $people ”
    --------------------
    Hello, everyone
    --------------------
    Hello, Hua Hua
    

    上述最后一条语句定义和传递参数一次性完成,有点匿名函数的味道。
    之前讲过定义函数也可以按照Begin, Process, End的结构,这样尤其可以实时处理管道数据。那能不能也直接通过语句块定义呢?

    Get-Service | Select-Object -Last 5 | & {
    	
    	begin {
    		Write-Host "初始化环境"
    	}
    	
    	process {
    		$_.Name
    	}
    	
    	end {
    		Write-Host "清理环境"
    	}
    }
    
    PS C:PowerShell> test.ps1                                                                            初始化环境
    XblGameSave
    XboxGipSvc
    XboxNetApiSvc
    ZeroConfigService
    ZoomCptService
    清理环境
    

    函数中的所有变量都是内置的,属于函数定义域。除非你指定给一个全局变量赋值。首先通过函数实现:

    function Test {
    	$value1 = 10
    	$global:value2 = 20
    }
    Test
    $value1
    $value2
    
    PS C:PowerShell> test.ps1                                                                            20
    

    那语句块也支持吗?例如:

    &{
    	$value1 = 10
    	$global:value2 = 20
    }
    $value1
    $value2
    
    PS C:PowerShell> test.ps1                                                                            20
    

    执行上下文

    Powershell 提供了一个非常特别的自动化变量,$ExecutionContext。这个变量可能会很少碰到,但是理解它的机制,有助于我们理解Powershell执行命令和脚本的内部机制。这个对象主要包含两个属性:InvokeCommandSessionState.

    PS C:PowerShell> $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解释器会自动处理该变量,并将变量替换成变量本身的值或者内容。

    PS C:PowerShell> $site = '飞苔博客'                                                                                    
    #双引号中的变量会被自动解析成变量的值:                                                              
    PS C:PowerShell> $text = "我的个人网站 $site"                                                                          PS C:PowerShell> $text                                                                                                 我的个人网站 飞苔博客
    

    既然双引号的机制是ExpandString()方法,那么也可以自己调用该方法

    PS C:PowerShell> $site = '飞苔博客'                                                                                    
    #双引号中的变量会被自动解析成变量的值:                                                              
    PS C:PowerShell> $text = "我的个人网站 $site"                                                                          PS C:PowerShell> $text                                                                                                 我的个人网站 飞苔博客
    #通过ExpandString()自动处理字符串中的变量                                                            
    PS C:PowerShell> $executioncontext.InvokeCommand.ExpandString($text)                                                   我的个人网站 飞苔博客
    

    创建脚本块

    如果将Powershell代码放置在{}中,这样既可以使用调用操作符&执行脚本,也可以将脚本块赋值给一个函数,因为之前的文章中说过,函数是一个命令的脚本块.

    # 创建新的脚本块
    $block = {
    	$write = Get-Process |Select-Object -First 1 
    	"$($write.Name) 占用内存: $($write.WorkingSet/1mb) MB"
    }
    
    $block.GetType().Name
    
    & $block
    	 
    # 使用NewScriptBlock方法创建脚本块:
    $blockStr = '$write=Get-Process |Select-Object -First 1 
    	"$($write.Name) 占用内存: $($write.WorkingSet/1mb) MB"'
    $block = $executioncontext.InvokeCommand.NewScriptBlock($blockStr)
    $block.GetType().Name
    & $block
    
    PS C:PowerShell> test.ps1                                                                            ScriptBlock
    1E.Client 占用内存: 6.48828125 MB
    ScriptBlock
    1E.Client 占用内存: 6.48828125 MB
    

    执行命令行

    输入的命令行可以通过InvokeScript()脚本执行,也可以使用&执行,也可以使用Invoke-Expression命令执行

    PS C:PowerShell> $cmd='3*3*3.14'                                                                                       PS C:PowerShell> & { 3*3*3.14}                                                                                         28.26
    PS C:PowerShell> $executioncontext.InvokeCommand.InvokeScript($cmd)                                                    28.26
    PS C:PowerShell> Invoke-Expression $cmd                                                                                28.26
    

    SessionState

    SessionState是一个用来表现Powershell环境的对象,你同样可以通过自动化变量$ExecutionContext访问这些信息.

    PS C:PowerShell> $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中所有的变量.

    PS C:PowerShell> $value = "Test"                                                                                       PS C:PowerShell> $executioncontext.SessionState.PSVariable.GetValue("value")                                           Test
    PS C:PowerShell> $executioncontext.SessionState.PSVariable.Set("value", 100)                                           PS C:PowerShell> $value                                                                                                100
    PS C:PowerShell> $executioncontext.SessionState.PSVariable.GetType().FullName                                          System.Management.Automation.PSVariableIntrinsics
    

    管理驱动器

    查看当前驱动器信息

    PS C:PowerShell> $ExecutionContext.SessionState.Drive.Current                                                          
    Name           Used (GB)     Free (GB) Provider      Root                                               CurrentLocation
    ----           ---------     --------- --------      ----                                               ---------------
    C                 238.34        236.62 FileSystem    C:                                                     PowerShell
    

    查看所有驱动器信息

    PS C:PowerShell> $ExecutionContext.SessionState.Drive.GetAll() | Format-Table                                          
    Name           Used (GB)     Free (GB) Provider      Root                                               CurrentLocation
    ----           ---------     --------- --------      ----                                               ---------------
    HKLM                                   Registry      HKEY_LOCAL_MACHINE
    HKCU                                   Registry      HKEY_CURRENT_USER
    Alias                                  Alias
    Env                                    Environment
    C                 238.34        236.62 FileSystem    C:                                                     PowerShell
    Function                               Function
    Variable                               Variable
    Cert                                   Certificate   
    WSMan                                  WSMan
    

    如果你的只想关注特定的驱动器,可以使用下面的方法:

    PS C:PowerShell> $ExecutionContext.SessionState.Drive.GetAllForProvider("FileSystem")                                  
    Name           Used (GB)     Free (GB) Provider      Root                                               CurrentLocation
    ----           ---------     --------- --------      ----                                               ---------------
    C                 238.34        236.61 FileSystem    C:                                                     PowerShell
    

    路径操作

    SessionState的Path包含几个特殊的方法,基本可以覆盖各种常用的路径操作

    方法 描述 对应的命令
    CurrentLocation 当前路径 Get-Location
    PopLocation() 获取存储的路径 Pop-Location
    PushCurrentLocation() 存储路径 Push-Location
    SetLocation() 定位路径 Set-Location
    GetResolvedPSPathFromPSPath() 相对路径转换成绝对路径 Resolve-Location
  • 相关阅读:
    Spark的精简安装步骤---陈楠心血总结
    关于Hadoop的集群环境下虚拟机采用NAT方式连不上网的解决
    size_t总结
    POJ 1852 Ants
    Digital Roots 1013
    1350. Primary Arithmetic
    Word Reversal
    POJ 2876 Cantoring Along
    逆序数的求法
    C++ 中cin
  • 原文地址:https://www.cnblogs.com/MerLin-LiuNian/p/15304380.html
Copyright © 2020-2023  润新知