PowerShell 技能连载 - 映射网络驱动器(第 1 部分)

PowerShell 支持控制台命令,所以如果您需要映射一个网络驱动器,通常最可靠的方式是使用传统好用的 net.exe,类似这样:

#requires -Version 1
net.exe use M: '\\dc-01\somefolder' /PERSISTENT:YES

Test-Path -Path M:\

explorer.exe M:\

如果您忽略“/PERSISTENT:YES”参数,那么映射的驱动器将只是临时的,注销并登录后将不会自动重连。

请注意如果驱动器号 M: 已在使用中,将会收到一个错误。将 M: 换成一个星号,将自动使用下一个可用的驱动器号。

要提交登录凭据,请使用这种方法:

net.exe use * '\\dc-01\somefolder' /PERSISTENT:YES /USER:training\user03 *

这将以 training\user03 的身份登录,并使用下一个可用的驱动器号,并且交互式地询问密码。请注意这只能在普通的 PowerShell 控制台中使用。它不能在 PowerShell ISE 中使用,因为 PowerShell ISE 并没有一个真实的控制台,所以无法交互式地询问密码。

要提交密码,将用户名之后的星号替换为密码。这当然不是很好的实践,因为这将把密码透露给所有可以查看代码的人。

PowerShell 技能连载 - 指定执行超时

Start-Process 可以启动进程但是不支持超时。如果您需要在指定的超时时间后结束一个跑飞了的进程,您可以使用类似这样的方法:

#requires -Version 2

$maximumRuntimeSeconds = 3

$process = Start-Process -FilePath powershell.exe -ArgumentList '-Command Start-Sleep -Seconds 4' -PassThru

try
{
    $process | Wait-Process -Timeout $maximumRuntimeSeconds -ErrorAction Stop
    Write-Warning -Message 'Process successfully completed within timeout.'
}
catch
{
    Write-Warning -Message 'Process exceeded timeout, will be killed now.'
    $process | Stop-Process -Force
}

Wait-Process 用于等待进程执行。如果它没有在指定的超时之内结束,Wait-Process 将抛出一个异常。在相应的错误处理器中可以决定要如何处理。

在这个例子中,catch 代码块将结束进程。

这个例子的处理代码是启动第二个 PowerShell 实例,在新的实例中执行 Start-Sleep 命令来模拟某些长时间运行的任务。如果您将 Start-Sleep 的参数调整为短于 $maximumRuntimeSeconds 指定的值,那么操作将会在指定的超时值之内完成,而您的脚本将不会结束该进程。

PowerShell 技能连载 - 以管理员身份执行指定的代码

如果您需要以管理员身份运行指定的脚本片段,您可以以管理员身份临时创建第二个 PowerShell 实例,然后在临时的实例中执行特权代码。

这是一段停止 Windows 更新服务的例子。当您以普通用户运行这段代码时,它将自动弹出提权的对话框,然后在一个新的管理员外壳中执行您的代码:

#requires -Version 2

Start-Process -FilePath powershell.exe -Verb runas -ArgumentList 'Stop-Service -Name wuauserv' -WindowStyle Minimized

PowerShell 技能连载 - 查找驱动器号

以下是一个查找保留驱动器号的简单函数:

#requires -Version 3

function Get-DriveLetter
{
    (Get-WmiObject -Class Win32_LogicalDisk).DeviceID
}

要列出所有正在使用的驱动器号,请使用以下代码:

PS> Get-DriveLetter
C:
D:
Y:
Z:

PS>

要查看某个给定的驱动器号是否被保留,可以使用这段代码:

PS> $letters = Get-DriveLetter

PS> $letters -contains 'c:'
True

PS> $letters -contains 'f:'
False

PS>

PowerShell 技能连载 - 快速设置多个环境变量

以下是一种快速(并且永久地)设置一系列环境变量的很棒的方法:

$hashtable = @{
    Name = 'Weltner'
    ID = 12
    Ort = 'Hannover'
    Type = 'Notebook'
    ABC = 123
}

$hashtable.Keys | ForEach-Object {
    $Name = $_
    $Value = $hashtable.$Name
    [Environment]::SetEnvironmentVariable($Name, $Value, "User")
}

只需要在一个哈希表中定义变量。该脚本将为每个键值对创建一个环境变量。将“User”替换为“Machine”,就可以创建系统级别的环境变量。不过这将需要管理员权限。

通过类似的方法,您也可以删除环境变量。只需要将空字符串赋值给哈希表中的值即可。

PowerShell 技能连载 - 快速查找脚本

要在“我的文档”文件夹的任意位置中快速定位一个 PowerShell 脚本,请试试这个 Find-Script 函数:

#requires -Version 3
function Find-Script
{
  param
  (
    [Parameter(Mandatory = $true)]
    $SearchPhrase,
    $Path = [Environment]::GetFolderPath('MyDocuments')
  )

  Get-ChildItem -Path $Path  -Filter *.ps1 -Recurse -ErrorAction SilentlyContinue |
  Select-String -Pattern $SearchPhrase -List |
  Select-Object -Property Path, Line |
  Out-GridView -Title "All Scripts containing $SearchPhrase" -PassThru |
  ForEach-Object -Process {
    ise $_.Path
  }
}

像这样运行:

Find-Script 'childitem'

这将返回一个在您的文档文件夹中包含搜索关键词的所有 PowerShell 脚本。当您在网格视图窗口中选择了某些脚本并点击确认按钮后,这些脚本将会自动由 PowerShell ISE 打开。

要设置一个不同的搜索跟路径,请使用 -Path 参数。通过这种方式,您可以很容易地在您的 USB 媒体或是网络路径中搜索。

PowerShell 技能连载 - 隐藏变量内容

当您覆盖某个对象的 ToString() 方法时,您就可以控制这个对象的显示方式。而这个对象的内容并不会被改变:

$a = 123
$a = $a | Add-Member -MemberType ScriptMethod -Name toString -Value { 'secret'} -Force -PassThru
$a
$a -eq 123
$a.GetType().FullName

例如,当一个变量表示字节数的时候,您甚至可以在您的自定义的 ToString() 方法中获取原始的变量值,然后将它显示为 MB(兆字节):

$a = 2316782313
$a = $a | Add-Member -MemberType ScriptMethod -Name toString -Value { [Math]::Round($this / 1MB,1) } -Force -PassThru
$a
$a -eq 123
$a.GetType().FullName

PowerShell 技能连载 - 向对象增加额外信息

当您获取结果信息时,您可能会希望向结果对象添加一些额外的属性,这样待会儿就可以知道它们是从哪儿来的。

向复杂类型对象添加额外的信息和向简单数据类型添加额外的信息不同(在前一个技能中有介绍)。

Get-Process |
  Add-Member -MemberType NoteProperty -Name PC -Value $env:COMPUTERNAME -PassThru |
  Select-Object -Property Name, Company, Description, PC |
  Out-GridView

这段代码中 Get-Process 返回的进程均被添加了一个名为“PC”的额外属性,用来存放进程所在的计算机名。

要查看自定义属性,要么使用 Select-Object 并指定属性名,要么使用点号语法:

$list = Get-Process |
  Add-Member -MemberType NoteProperty -Name PC -Value $env:COMPUTERNAME -PassThru

$list | ForEach-Object { 'Process {0} on {1}' -f $_.Name, $_.PC }

PowerShell 技能连载 - 向原始数据类型增加额外信息

也许您希望对一个变量做标记并提供一些额外信息。在 PowerShell 中,可以使用 Add-Member 来向一个变量附加 NoteProperties 或 ScriptProperties。

一个 NoteProperty 包含一些静态信息,而当我们获取一个 ScriptProperty 的值时,将会运行一段代码。

请看如何对一个简单的字符串做操作:

$a = "some text"

$a = $a | Add-Member -MemberType NoteProperty -Name Origin -Value $env:computername -PassThru
$a = $a | Add-Member -MemberType ScriptProperty -Name Time -Value { Get-Date } -PassThru

$a
$a.Origin
$a.Time

PowerShell 技能连载 - 简单的 INI 文件替代

如果您想将设置保存在您的脚本之外并将它们保存在一个独立的配置文件中,那么您可以使用各种数据格式。

INI 文件的并地支持并不充分,所以您得人工处理它们。JSON 和 XML 文件有处理器支持,但是文字内容太复杂,不容易被人类阅读。

If your config data can be expressed as key-value pairs like below, then we have an alternative:
如果您的配置数据是类似这样的键值对,那么我们可以有别的选择:

1
2
3
Name = 'Tom'
ID = 12
Path = 'C:'

将键值对保存为一个纯文本文件,然后使用这段代码来读取该文件:

$hashtable = @{}
$path = 'z:\yourfilename.config'

$payload = Get-Content -Path $path |
Where-Object { $_ -like '*=*' } |
ForEach-Object {
    $infos = $_ -split '='
    $key = $infos[0].Trim()
    $value = $infos[1].Trim()
    $hashtable.$key = $value
}

结果是一个哈希表,您可以用这种方式轻松地读取各项的值:

$hashtable.Name
$hashtable.ID
$hashtable.Path