PowerShell 技能连载 - 在计划任务中运行 PowerShell 脚本

如果您需要以固定的频率运行一段 PowerShell 脚本,何不以计划任务的方式运行它呢?以下是一段帮您新建一个每天上午 6 点执行一个 PowerShell 脚本的计划任务的代码:

1
2
3
4
5
6
7
8
9
10
11
#requires -Modules ScheduledTasks
#requires -Version 3.0
#requires -RunAsAdministrator

$TaskName = 'RunPSScriptAt6'
$User= "train\tweltner"
$scriptPath = "\\Server01\Scripts\find-newaduser.ps1"

$Trigger= New-ScheduledTaskTrigger -At 6:00am -Daily
$Action= New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "-executionpolicy bypass -noprofile -file $scriptPath"
Register-ScheduledTask -TaskName $TaskName -Trigger $Trigger -User $User -Action $Action -RunLevel Highest -Force

PowerShell 技能连载 - 查看函数源码

以下是一种快速查看 PowerShell 函数源码的方法:

1
${function:Clear-Host} | clip

这将会把 Clear-Host 的源代码复制到剪贴板中,并且当您粘贴它时,您可以看到 Clear-Host 是如何工作的:

1
2
3
4
5
$RawUI = $Host.UI.RawUI
$RawUI.CursorPosition = @{X=0;Y=0}
$RawUI.SetBufferContents(
@{Top = -1; Bottom = -1; Right = -1; Left = -1},
@{Character = ' '; ForegroundColor = $rawui.ForegroundColor; BackgroundColor = $rawui.BackgroundColor})

通常可以从这里学到很多东西。如果您想用非空格的字符填充 PowerShell 控制台,例如绿底白字的 ‘X’,请试试这段代码:

1
2
3
$host.UI.RawUI.SetBufferContents(
@{Top = -1; Bottom = -1; Right = -1; Left = -1},
@{Character = 'X'; ForegroundColor = 'Yellow'; BackgroundColor = 'Green'})

请注意这只能在真正的 PowerShell 控制台宿主中起作用。

PowerShell 技能连载 - More 命令的现代版替代品

在 PowerShell 控制台中,您仍然可以用 more 管道,就像在 cmd.exe 中一样一页一页查看结果。然而,more 不支持实时管道,所以所有数据需要首先收集好。这将占用很长时间和内存:

1
dir c:\windows -Recurse -ea 0  | more

一个更好的方法是使用 PowerShell 自带的分页功能:

1
dir c:\windows -Recurse -ea 0  | Out-Host -Paging

请注意这些都需要一个真正的控制台窗口,而在图形界面的宿主中不能工作。

PowerShell 技能连载 - 远程创建 SMB 共享

以下几行代码能在远程服务器上创建一个 SMB 共享:

1
2
3
4
5
6
7
8
#requires -Version 3.0 -Modules CimCmdlets, SmbShare -RunAsAdministrator
$computername = 'Server12'
$shareName = 'ScriptExchange'
$fullAccess = 'domain\groupName'

$session = New-CimSession -ComputerName $computername
New-SMBShare -Name $shareName -Path c:\Scripts -FullAccess $fullAccess -CimSession $session
Remove-CimSession -CimSession $session

您可以在客户端将该共享映射为一个网络驱动器。请注意这个网络共享是单用户的,所以如果您使用 Administrator 账户做了映射,那么无法在 Windows Explorer 中存取。

1
2
3
$computername = 'Server12'
$shareName = 'ScriptExchange'
net use * "\\$computername\$shareName"

PowerShell 技能连载 - 重要的 PowerShell 变量

以下是一个重要的 PowerShell 变量的列表:$pshome 表示 PowerShell 所在的位置。$home 是个人用户配置文件夹的路径。$PSVersionTable 返回 PowerShell 的版本和重要的子组件的版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
PS> $pshome
C:\Windows\System32\WindowsPowerShell\v1.0

PS> $HOME
C:\Users\tweltner

PS> $PSVersionTable

Name Value
---- -----
PSVersion 5.1.14393.0
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.14393.0
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1

$profile 是您个人的自启动脚本所在的位置。每当您当前的 PowerShell 宿主启动时,自启动脚本就会自动加载(假设文件存在)。$profile.CurrentUserAllHosts 是任何宿主都会加载的配置文件脚本。并且 $env:PSModulePath 列出 PowerShell 可以自动发现的存放 PowerShell module 的文件夹:

1
2
3
4
5
6
7
8
9
10
11
12
PS> $profile
C:\Users\tweltner\Documents\WindowsPowerShell\Microsoft.PowerShellISE_profile.ps1

PS> $profile.CurrentUserAllHosts
C:\Users\tweltner\Documents\WindowsPowerShell\profile.ps1

PS> $env:PSModulePath -split ';'
C:\Users\tweltner\Documents\WindowsPowerShell\Modules
C:\Program Files\WindowsPowerShell\Modules
C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules

PS>

PowerShell 技能连载 - Read-Host 阻塞自动化操作

使用 Read-Host 向用户提示输入信息可能会造成问题,因为它影响了脚本的自动化运行。一个更好的方法是将 Read-Host 包装在 param() 代码块中。通过这种方式,该信息可以通过无人值守操作的参数传入,也可以通过交互式提示传入:

1
2
3
4
5
6
7
8
param
(
$Name = $(Read-Host -Prompt 'Enter your name'),
$Id = $(Read-Host -Prompt 'Enter your ID')
)


"You are $Name and your ID is $Id"

当您运行以上脚本时,它像 Read-Host 一模一样地显示提示信息。您也可以通过参数执行该脚本:

1
PS> C:\myscript.ps1 –Name test –Id 12

If you do not need custom prompting, you can go even simpler, and declare parameters as mandatory by adding [Parameter(Mandatory)] above each parameter variable.
如果您不需要自定义提示信息,您还可以更加简单,只需要在每个参数变量上加上 [Parameter(Mandatory)] 使它们变为必需参数。

PowerShell 技能连载 - 映射网络驱动器

PowerShell 提供很多种方式来连接到 SMB 文件共享。以下是三种不同的方法:

1
2
3
4
5
6
# adjust path to point to your file share
$UNCPath = '\\server\share'

net use * $UNCPath
New-PSDrive -Name y -PSProvider FileSystem -Root $UNCPath -Persist
New-SmbMapping -LocalPath 'x:' -RemotePath $UNCPath

Net.exe 是最多功能的方法,在 PowerShell 的所有版本中都有效。通过传入一个 “*”,它自动选择下一个有效的驱动器盘符。

New-PSDrive 从 PowerShell 3 起支持 SMB 共享。New-SmbMapping 需要 SmbShare 模块并且现在看来有点古怪:重启后才能在 Windows Explorer 中显示该驱动器。

PowerShell 技能连载 - 安全地删除数据

要安全地删除文件、文件夹,或整个驱动器,PowerShell 可以使用内置的 cipher.exe 工具。这行代码可以安全地删除旧的用户配置文件:

1
Cipher.exe /w:c:\Users\ObsoleteUser

请注意要删除的文件夹路径和参数 /w 之间需要用一个 : 分隔。删除数据需要消耗一定时间:Windows 要多次覆盖整个数据内容,以确保它不可恢复。

PowerShell 技能连载 - 查找 OU

(来自 Microsoft 免费的 RSAT 工具的)Get-OrganizationalUnit 可以基于识别名或 GUID 来搜索 OU,或者可以使用 -Filter 参数。

不幸的是,-Filter 不能方便地自动化。以下代码并不能工作,并不能返回所有名字中包含 “Test” 的 OU:

1
2
$Name = 'Test'
Get-ADOrganizationalUnit -Filter { Name -like "*$Name*" }

这个结果很令人惊讶,因为以下这行代码可以工作(前提是您确实有名字包含 “Test” 的 OU):

1
Get-ADOrganizationalUnit -Filter { Name -like "*Test*" }

通常情况下,如果您想用简单的通配符来搜索,那么使用简单的 LDAP 过滤器十分管用。以下代码查找所有名字中包含 “Test” 的 OU:

1
2
$Name = 'Test'
Get-ADOrganizationalUnit -LDAPFilter "(Name=*$Name*)"
PowerShell 技术 QQ 群