PowerShell命令与脚本(10)——脚本

Posted Ulysse

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PowerShell命令与脚本(10)——脚本相关的知识,希望对你有一定的参考价值。

编写和运行脚本

一个Powershell仅仅是一个包含Powershell代码的文本文件。如果这个文本文件执行,Powershell解释器会逐行解释并执行它的的语句。Powershell脚本非常像以前CMD控制台上的批处理文件。您可以通过非常简单的文本编辑工具创建Powershell脚本。
1、编写PowerShell脚本
  • 通过重定向创建脚本
如果您的脚本不是很长,您甚至可以直接在控制台中要执行的语句重定向给一个脚本文件。
这样有个缺点,就是您的代码必须放在闭合的引号中。这样的书写方式一旦在脚本内部也有引号时,是一件很痛苦的事。甚至您还可能希望在脚本中换行。下面的Here-strings例子不错,也就是将脚本文件通过@‘ ’@闭合起来。
Here-String以 @‘开头,以’@结束.任何文本都可以存放在里面,哪怕是一些特殊字符,空号,白空格。但是如果您不小心将单引号写成了双引号,Powershell将会把里面的变量进行解析。
 
  • 通过编辑器创建脚本
其实非常方便的还是最地道的文版编辑器Notepad,您可以直接在Powershell控制台中打开Notepad
notepad.exe .\\MyScript.ps1
编辑完记得保存即可。
 
 
2、运行PowerShell脚本
当您的脚本编写成功后您可能第一次会像下面的方式运行它,也就是只输入脚本的文件名,会报错。
除非您使用相对路径,或者绝对路径。
 
执行策略限制
Powershell一般初始化情况下都会禁止脚本执行。脚本能否执行取决于Powershell的执行策略。
只有管理员才有权限更改这个策略。非管理员会报错。
查看脚本执行策略,可以通过 Get-ExecutionPolicy
更改脚本执行策略,可以通过 Set-ExecutionPolicy UnRestricted
 
脚本执行策略类型为:Microsoft.PowerShell.ExecutionPolicy
查看所有支持的执行策略:[System.Enum]::GetNames([Microsoft.PowerShell.ExecutionPolicy])
Unrestricted:权限最高,可以不受限制执行任何脚本。
Default:为Powershell默认的策略:Restricted,不允许任何脚本执行。
AllSigned:所有脚本都必须经过签名才能在运行。
RemoteSigned:本地脚本无限制,但是对来自网络的脚本必须经过签名。
 

给脚本传递参数

怎样将一个脚本稍作润色,让它能够根据用户的输入,处理并输出相应的结果,而不是只产生一成不变的输出。怎样将参数传递给脚本,这是本节讨论的内容。
 
1、$args返回所有的参数
传递给一个函数或者一个脚本的参数都保存在$args变量中。可以先打开记事本,输入脚本:
Write-Host "Hello,$args"
保存后,通过控制台执行脚本:
 
2、$args数组参数
默认情况下,传递给一个Powershell脚本的参数类型为数组,例如:
上面的文本中包含多个连续的空格,可是当脚本把参数输出时却不存在连续的空格了。那是因为脚本会把文本根据白空格截断并转换成数组。如果不想文本被当成数组那就把它放在引号中。
在$args中逐个访问参数
因为$args是一个数组,自然可以通过索引访问数组的每一个元素。可以将MyScript.sp1的内容改为:
For($i=0;$i -lt $args.Count; $i++)
{
    Write-Host "parameter $i : $($args[$i])"
}
然后在控制台测试:
 
3、在脚本中使用参数名
通过Powershell传递参数固然方便,但是如果用户不知道参数的传递顺序,也是很郁闷的,例如在Myscript.ps1中输入:
$args[0]-$args[1]
执行脚本发现参数的顺序不同,结果也不同:
所以最好的方式给参数指定名称,输入以下的脚本:
param($Directory,$FileName)
 
"Directory= $Directory"
"FileName=$FileName"
其中param给参数指定名称。
执行脚本:
 
4、验证参数
给脚本的参数绑定数据类型,绑定帮助信息。一旦脚本缺少参数,或者输入的参数类型不正确,就提醒用户:
输入脚本:
param(
[string]$Name=$(throw "Parameter missing: -name Name") ,
[int]$Age=$(throw "Parameter missing: -age x as number")
)
 
"Name= $Name"
"Age=$Age"
执行脚本:
 
5、变量的作用域
Powershell默认使用全局作用域global: ,但是在函数和脚本中分别使用函数作用域function:和脚本作用域script: 。
一旦脚本执行结束,存在于脚本作用域的变量也会消失。但是有一点,如果一个变量在脚本外定义,在脚本内没有定义,在脚本内使用时会把外面的变量引渡过来。
在脚本中输入:
$temp
执行脚本:
在脚本中尝试改变变量$temp,但是脚本内的变量不会影响脚本外的变量,输入脚本:
$temp="powershell is soooooo good"
$temp
执行脚本:
 

PowerShell增强脚本的可读性

如果你愿意,你可以把一个脚本写的非常长,问题是脚本的代码量越大,可读性越差。最好的方式在写脚本时融入函数和类库的概念:
函数:把实现一些小功能的代码写成一个函数,不仅可以增强代码的可读性,还可以很方便的重用。一旦你创建了一个实现特定功能的函数,也可以下次在其它脚本中使用。
类库:把需要的函数嵌入进类库中,就不用每次在执行脚本时拷贝函数,并且还可以在需要时扩充它。另外以函数的方式构建类库,还可以让你更专注特定功能的具体实现,降低脚本开发的复杂度。
 
1、在脚本中使用函数
要在脚本中使用函数,最简单的方法自然是将函数直接写在脚本中:
在MyScript.ps1中输入:
param([int]$n=$(throw "请输入一个正整数"))
Factorial $n
Function Factorial([int]$n)
{
    $total=1
    for($i=1;$i -le $n;$i++)
    {
        $total*=$i
    }
    return $total
}
这个脚本接收一个正整数参数,然后通过Factorial函数求阶乘。
不像其它脚本语言,Powershell中的函数必须先定义后使用
所以更改脚本为:
param([int]$n=$(throw "请输入一个正整数"))
Function Factorial([int]$n)
{
    $total=1
    for($i=1;$i -le $n;$i++)
    {
        $total*=$i
    }
    return $total
}
Factorial $n
执行脚本:
 
2、将脚本分为工作脚本和类库
真正的脚本开发需要处理的问题可能包含许多函数。如果在一个脚本的开头定义许多函数,脚本会显得很凌乱。把函数和工作脚本分开,可以隔离函数,使它不容易被修改。
将Factorial函数保存在PSLib.ps1
Function Factorial([int]$n)
{
    $total=1
    for($i=1;$i -le $n;$i++)
    {
        $total*=$i
    }
    return $total
}
将MyScript.ps1脚本修改为:
param([int]$n=$(throw "请输入一个正整数"))
. .\\PSLib.ps1
Factorial $n
执行脚本:
脚本在执行时,先加载类库中的函数。加载函数类库和执行脚本类似,只需要在前面增加一个句号,中间有空格。
 
3、类库脚本集中存放
在开始使用类库脚本工作之前,最好先制定出一个存储脚本类库的策略。一种方法是和工作脚本存放在一起,可以使用相对路径;另一种方法是分开存放,加载时就得使用绝对路径了。最好在当前用户的私人目录中存放脚本,相对来说比较安全。
 
 

创建管道脚本

我们可以像创建管道函数那样创建管道脚本,具体采用低速顺序模式,还是高速流模式,这取决于具体的编程实现。
1、低速顺序模式
如果你在脚本中使用管道,脚本收集上一个语句的执行结果,默认保存在$input自动变量中。但是直到上一条语句完全执行彻底,管道脚本才会执行。
创建脚本:
pipeline.ps1
foreach($element in $input)
{
	if($element.Extension -eq ".exe")
	{
		Write-Host -fore "red" $element.Name
	}
	else
	{
		Write-Host -fore "Green" $element.Name
	}
}
执行脚本:
ls $env:windir | .pipeline.ps1
如果这样执行:
ls $env:windir -Recurse | .pipeline.ps1
控制台会被冻结,因为存储的中间结果在玩命的吃内存。这个也是低速顺序模式的缺点。
 
2、高速流模式
在Powershell脚本的处理中,绝大多数情况下遇到的都是集合,一旦上一条命令产生一个中间结果,下一条命令就对这个中间结果及时处理,及时释放资源。这样可以节省内存,也减少了用户的等待时间。在处理大量数据时,尤其值得推荐。高速流模式的管道定义包括三部分:begin,process,end。上面的描述中提到了中间结果,中间结果保存在$_自动化变量中。
begin
{
	Write-Host -fore "Green" "管道脚本环境初始化"
}
process
{
	$ele=$_
	if($_.Extension -ne "")
	{
		switch($_.Extension.tolower())
		{
			".ps1" {"ps1脚本文件:"+$ele.name}
			".vbs" {"vbs脚本文件:"+$ele.name}
			".txt" {"txt文本文件:"+$ele.name}
		}
	}
}
end
{
	Write-Host -fore "Yellow" "管道脚本环境恢复"
}
执行脚本文件:
 

自动执行脚本之profile

在Powershell控制台的许多更改只会在当前会话有效。一旦关闭当前控制台,你自定义地所有别名、函数、和其它改变将会消失,除非将更改保存在windows环境变量中。这也就是为什么我们需要profile来保存一些基本的初始化工作。
 
四中不同的profile脚本
Powershell支持四种可以用来初始化任务的profile脚本。应用之前要弄清楚你的初始化是当前用户个人使用,还是所有用户。如果是个人使用,可以使用”当前用户profile“,但是如果你的初始化任务是针对所有用户,可是使用“所有用户profile”。
Profile
描述
位置
所有用户
所有用户共有的profile
$pshome\\profile.ps1
所有用户(私有)
powershell.exe 中验证。
$pshome\\Microsoft.PowerShell_profile.ps1
当前用户
当前用户的profile
$((Split-Path $profile -Parent)+ “\\profile.ps1”)
当前用户(私有)
当前用户的profile;只在Powershell.exe中验证
$profile
我们注意到上面的四种profile有两个private。一旦声明为private,只有个microsoft的Powershell自身才会去调用,不会对其它引用powershell的组件有效。
 
创建自己的profile
Profile脚本并不是强制性的,换言之,profile可有可无。下面会很方便的创建自己的profile。 在控制台执行: notepad $profile 如果不存在profile默认会创建,在打开的记事本中输入: Set-Alias edit notepad.exe
也就是给notepad添加edit别名,保存关闭,之后重启控制台,输入: edit
控制台会打开记事本打开,可见edit别名已经生效。
 
创建全局profile
创建全局的profile也是很容易的,如上,只是文件的位置稍有改变; 需要注意的是,创建全局profile需要管理员权限,没有管理员权限,该文件或者文件夹拒绝访问。还有一点也须注意:在vista系统中,即使你拥有管理员权限,但是没有通过administrator登录,并且系统没有禁用UAC,也是拒绝更改的。除非你鼠标右键单击Powershell快捷方式,以管理员权限运行。
 

 

以上是关于PowerShell命令与脚本(10)——脚本的主要内容,如果未能解决你的问题,请参考以下文章

Powershell命令处理(传入变量)

win10 powershell禁止运行脚本解决

获取PowerShell脚本的文字命令行

win2008如何在用bat调出的powershell窗口里运行命令

powershell脚本隐藏退出码

如何在命令行执行 powershell 脚本