PowerShell 技能连载 - 按数据类型绑定参数

PowerShell 可以根据数据类型匹配自动地绑定参数。以下是一个体现该特性的示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function Test-Binding
{
[CmdletBinding(DefaultParameterSetName='Date')]
param
(
[Parameter(ParameterSetName='Integer', Position=0, Mandatory=$true)]
[int]
$Id,
[Parameter(ParameterSetName='String', Position=0, Mandatory=$true)]
[string]
$Name,
[Parameter(ParameterSetName='Date', Position=0, Mandatory=$true)]
[datetime]
$Date
)
$chosenParameterSet = $PSCmdlet.ParameterSetName
Switch ($chosenParameterSet)
{
'Integer' { 'User has chosen Integer' }
'String' { 'User has chosen String' }
'Date' { 'User has chosen Date' }
}
[PSCustomObject]@{
Integer = $Id
String = $Name
Date = $Date
}
}

现在用户可以测试 Test-Binding 并且提交参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
PS C:\> Test-Binding "Hello"
User has chosen String
Integer String Date
------- ------ ----
0 Hello
PS C:\> Test-Binding 12
User has chosen Integer
Integer String Date
------- ------ ----
12
PS C:\> Test-Binding (Get-Date)
User has chosen Date
Integer String Date
------- ------ ----
0 11/21/2017 11:44:33 AM

查看更多

评论

PowerShell 技能连载 - 删除环境变量

在前一个技能中我们解释了如何在所有可用的范围内设置环境变量的方法。但是如何移除环境变量呢?

巧合地,您可以用完全相同的方法做这件事情,只需要将一个空字符串赋给该变量。然而,前一个技能中的函数中的 -VariableValue 参数不能接受空字符串:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Set-EnvironmentVariable
{
[CmdletBinding()]
param
(
[Parameter(Mandatory)][String]
$VariableName,
[Parameter(Mandatory)][String]
$VariableValue,
[Parameter(Mandatory)][EnvironmentVariableTarget]
$Target
)
[Environment]::SetEnvironmentVariable($VariableName, $VariableValue, $Target)
}

当您尝试着赋值空字符串时,将会收到这样的提示:

1
2
3
PS C:\> Set-EnvironmentVariable -VariableName test -VariableValue "" -Target User
Set-EnvironmentVariable : Cannot bind Argument to Parameter "VariableValue" because it is an empty string.
...

这是因为当您将一个参数声明为 “Mandatory”,PowerShell 缺省情况下将拒绝空字符串和 null 值。

您可以将 VariableValue 参数设为可选的,但是这样当您调用该函数不传该参数时,PowerShell 将不再提示。如何使一个必选参数能接受 null 和空字符串呢?

只要稍微改一下,加上 [AllowNull()] 和/或 [AllowEmptyString()] 以上函数就可以支持删除环境变量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function Set-EnvironmentVariable
{
[CmdletBinding()]
param
(
[Parameter(Mandatory)][String]
$VariableName,
[Parameter(Mandatory)][String]
[AllowEmptyString()]
$VariableValue,
[Parameter(Mandatory)][EnvironmentVariableTarget]
$Target
)
[Environment]::SetEnvironmentVariable($VariableName, $VariableValue, $Target)
}

以下是删除 “Test” 环境变量的方法:

1
PS C:\> Set-EnvironmentVariable -VariableName test -VariableValue "" -Target User

查看更多

评论

PowerShell 技能连载 - 设置环境变量

有些时候您会见到一些脚本使用 Select-Object 向现有的对象附加信息,类似以下代码:

1
2
3
4
5
6
Get-Process |
Select-Object -Property *, Sender|
ForEach-Object {
$_.Sender = $env:COMPUTERNAME
$_
}

它可以工作,但是 Select-Object 创建了一个完整的对象拷贝,所以这种方法速度很慢而且改变了对象的类型。您可能注意到了 PowerShell 不再使用正常的表格方式输出进程对象,也是因为这个原因。

如果您想设置环境变量,env: 驱动器只能修改进程级别的环境变量。要设置用户或者机器级别的环境变量,请试试这个函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Set-EnvironmentVariable
{
[CmdletBinding()]
param
(
[Parameter(Mandatory)][String]
$VariableName,
[Parameter(Mandatory)][String]
$VariableValue,
[Parameter(Mandatory)][EnvironmentVariableTarget]
$Target
)
[Environment]::SetEnvironmentVariable($VariableName, $VariableValue, $Target)
}

请注意 $Target 变量如何使用特殊的数据类型 “EnvironmentVariableTarget” ,当您在 PowerShell ISE 或其它带有 IntelliSense 功能的编辑器中,-Target 参数的可选项有 “Process”、”User” 和 “Machine”。

以下是如何在用户级别创建名为 “Test”,值为 12 的环境变量的方法:

1
2
3
PS C:\> Set-EnvironmentVariable -VariableName test -VariableValue 12 -Target User
PS C:\>

查看更多

评论

PowerShell 技能连载 - 在剪贴板中附加内容

PowerShell 5 带来了新的将文本复制到剪贴板,以及取出剪贴板文本的 cmdlet:Set-ClipboardGet-Clipboard

Set-Clipboard 也支持 -Append 参数,它可以向剪贴板尾部附加文本。这可以成为一种新奇且有用的记录脚本行为的方法:

1
2
3
4
5
6
7
8
9
10
Set-ClipBoard "Starting at $(Get-Date)"
1..30 |
ForEach-Object {
Set-ClipBoard -Append "Iteration $_"
$wait = Get-Random -Minimum 1 -Maximum 5
Set-ClipBoard -Append "Waiting $wait seconds"
Start-Sleep -Seconds $wait
"Processing $_"
}

这个脚本片段使用 Set-Clipboard 将信息粘贴至剪贴板中。脚本运行后,您可以将剪贴板内容粘贴至剪贴板来查看脚本输出的日志。

查看更多

评论

PowerShell 技能连载 - 删除用户配置文件

当一个用户登录计算机时,将创建一套用户配置文件。在前一个技能中我们介绍了如何用 PowerShell 转储计算机中的用户配置文件列表。

如果您想删除一个用户账户,PowerShell 可以帮您清除。以下是使用方法:

首先,调整 $domain$username 变量指向您想删除的用户配置文件。然后,在 PowerShell 中以管理员特权运行以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
#requires -RunAsAdministrator
$domain = 'ccie'
$username = 'user01'
# get user SID
$sid = (New-Object Security.Principal.NTAccount($domain, $username)).Translate([Security.Principal.SecurityIdentifier]).Value
Get-WmiObject -ClassName Win32_UserProfile -Filter "SID='$sid'" |
ForEach-Object {
$_.Delete()
}

第一部分将用户名转换为 SID 并且用它来指定用户配置文件。WMI 的 Delete() 方法删除所有用户配置文件。注意:您将丢失删除的用户配置文件中的所有数据。

查看更多

评论

PowerShell 技能连载 - 管理用户配置文件

要转储一台机子上用户配置文件的原始列表,请使用这行代码:

1
Get-CimInstance -Class Win32_UserProfile | Out-GridView

您将会获得所有用户配置文件的所有详细信息。用户名可以在 SID 属性中找到,但它是以 SID 的格式表示。要获得真实的用户名,需要将 SID 转换。这段代码创建一个以真实用户名为字段名的哈希表:

1
2
3
4
5
6
7
$userProfiles = Get-CimInstance -Class Win32_UserProfile |
# add property "UserName" that translates SID to username
Add-Member -MemberType ScriptProperty -Name UserName -Value {
([Security.Principal.SecurityIdentifier]$this.SID).Translate([Security.Principal.NTAccount]).Value
} -PassThru |
# create a hash table that uses "Username" as key
Group-Object -Property UserName -AsHashTable -AsString

现在可以轻松地转储机器上所有带用户配置文件的用户列表了:

1
2
3
4
5
6
7
8
9
10
PS C:\> $userProfiles.Keys | Sort-Object
MYDOMAIN\Administrator
MYDOMAIN\User01
MYDOMAIN\User02
MYDOMAIN\User03
MYDOMAIN\User12
NT AUTHORITY\LOCAL SERVICE
NT AUTHORITY\NETWORK SERVICE
NT AUTHORITY\SYSTEM
PC10\User

要获取某个用户配置文件的详细信息,请访问哈希表的字段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
PS C:\> $userProfiles["MYDOMAIN\User01"]
UserName : MYDOMAIN\User01
AppDataRoaming : Win32_FolderRedirectionHealth
Contacts : Win32_FolderRedirectionHealth
Desktop : Win32_FolderRedirectionHealth
Documents : Win32_FolderRedirectionHealth
Downloads : Win32_FolderRedirectionHealth
Favorites : Win32_FolderRedirectionHealth
HealthStatus : 3
LastAttemptedProfileDownloadTime :
LastAttemptedProfileUploadTime :
LastBackgroundRegistryUploadTime :
LastDownloadTime :
LastUploadTime :
LastUseTime :
Links : Win32_FolderRedirectionHealth
Loaded : False
LocalPath : C:\Users\User01
Music : Win32_FolderRedirectionHealth
Pictures : Win32_FolderRedirectionHealth
RefCount :
RoamingConfigured : False
RoamingPath :
RoamingPreference :
SavedGames : Win32_FolderRedirectionHealth
Searches : Win32_FolderRedirectionHealth
SID : S-1-5-21-3860347202-3037956370-3782488958-1604
Special : False
StartMenu : Win32_FolderRedirectionHealth
Status : 0
Videos : Win32_FolderRedirectionHealth
PSComputerName :

查看更多

评论

PowerShell 技能连载 - 在多台计算机中并行运行命令

假设您已经启用了 PowerShell 远程处理(请看我们之前的技能),那么您可以同时在多台计算机上运行命令。

以下例子演示了这个操作,并且在列表中所有计算机中所有用户的桌面上放置一个文件。警告:这是个很强大的脚本。它将在列表中的所有机器上运行 $code 中的任何代码,假设启用了远程处理,并且您有相应的权限:

1
2
3
4
5
6
7
8
9
10
# list of computers to connect to
$listOfComputers = 'PC10','TRAIN1','TRAIN2','AD001'
# exclude your own computer
$listOfComputers = $listOfComputers -ne $env:COMPUTERNAME
# code to execute remotely
$code = {
"Hello" | Out-File -FilePath "c:\users\Public\Desktop\result.txt"
}
# invoke code on all machines
Invoke-Command -ScriptBlock $code -ComputerName $listOfComputers -Throttle 1000

例如,如果您将 $code 中的代码替换为 Stop-Computer -Force,所有机器将会被关闭。

查看更多

评论

PowerShell 技能连载 - 通过 PowerShell 远程处理操作远程机器

当您在目标机器上启用了 PowerShell 远程处理,请试试交互式地连接它。以下是您值得尝试的例子。只需要确保将 targetComputerName 替换成您需要连接的目标机器名即可:

1
2
3
4
5
6
7
8
9
PS C:\> Enter-PSSession -ComputerName targetComputerName
[targetComputerName]: PS C:\Users\User12\Documents> $env:COMPUTERNAME
TARGETCOMPUTERNAME
[targetComputerName]: PS C:\Users\User12\Documents> exit
PS C:\> $env:COMPUTERNAME
YOURCOMPUTERNAME

如果连接失败并且报 “Access Denied” 错误,您可能需要使用 -Credential 参数并且使用一个不同的用户账户来登录远程计算机。您可能需要本地管理员特权。

如果连接失败并且报告 RDP 错误,或者如果 WinRM 无法找到目标计算机名,请使用 Test-WSMan 检查连接。如果这无法连接上,请重新检查远程设置。您可能需要像之前的技能中描述的那样,先在目标机器上运行 Enable-PSRemoting

请不要运行会打开窗口的命令。只能运行产生文本信息的命令。

要离开远程会话,请使用 exit 命令。

查看更多

评论

PowerShell 技能连载 - 使用 PowerShell 远程处理

如果您想试试 PowerShell 远程处理,您至少需要在目标机器(您希望访问的机器)上启用它。要使用它,您需要目标机器上的本地管理员特权。请用管理员特权打开 PowerShell,并且运行以下代码:

1
2
3
4
#requires -RunAsAdministrator
# manually enable PowerShell remoting
Enable-PSRemoting -SkipNetworkProfileCheck -Force

接下来,在另一台能通过网络访问的计算机上,运行运行 PowerShell 远程处理的 “Ping“ 来测试是否能连上目标机器:

1
2
3
4
# "ping" for PowerShell remoting
# tests anonymously whether you can reach the target
$IPorNameTargetComputer = 'place name or IP address here'
Test-WSMan $IPorNameTargetComputer

当目标机器响应时,Test-WSMan 返回类似以下的文本。它进行了一个匿名测试,所以如果它失败了,您就知道防火墙或者目标机器的配置有问题。

wsmid           : http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd
ProtocolVersion : http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd
ProductVendor   : Microsoft Corporation
ProductVersion  : OS: 0.0.0 SP: 0.0 Stack: 3.0 

在下一个技能中,我们将看看能用 PowerShell 远程处理来做什么,以及如何远程执行脚本。

查看更多

评论

PowerShell 技能连载 - 以 JSON 格式读取和保存选项

如果您想在脚本中保存信息,您也许希望将数据保存成 JSON 格式的对象。以下是一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# define options object
$options = [PSCustomObject]@{
Color = 'Red'
Height = 12
Name = 'Weltner'
}
# play with options settings
$options.Color = 'Blue'
# save options to file
$Path = "c:\test\options.json"
$options | ConvertTo-Json | Set-Content -Path $Path
# load options from file
$options2 = Get-Content -Path $Path | ConvertTo-Json

请确保路径 “c:\test” 存在。脚本将创建一个包含指定数据的自定义对象,并将它以 JSON 的格式保存到磁盘。下一步,数据将在您需要的时候读取出来。例如在另外一个脚本中,或读取初始设置时。

查看更多

评论