PowerShell 技能连载 - 查找 PowerShell 宿主参数和可执行文件

PowerShell 宿主可以使用参数启动,即您可以使用 –NoProfile 之类的参数运行 powershell.exepwsh.exe,或提交要执行的脚本的路径。

在外壳中,您始终可以查看启动此外壳程序的命令,包括其他参数:

1
2
3
$exe, $parameters = [System.Environment]::GetCommandLineArgs()
"EXE: $exe"
"Args: $parameters"

当您使用 -NoProfile 启动 powershell.exe 时,结果如下所示:

EXE: C:\WINDOWS\system32\WindowsPowerShell\v1.0\PowerShell.exe Args: -noprofile

当您传入多个参数时,$parameters 是一个数组。

PowerShell 技能连载 - 管理已安装的模块(第 2 部分)

每当您通过 Install-Module 安装新模块或通过 Update-Module 更新现有模块时,新模块版本就会并行地安装。

如果您始终使用最新版本的模块,而无需访问特定的旧版本,则可能需要查找过时的模块并将其删除:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# get all installed modules as a hash table
# each key holds all versions of a given module
$list = Get-InstalledModule |
Get-InstalledModule -AllVersions |
Group-Object -Property Name -AsHashTable -AsString

# take all module names...
$list.Keys |
ForEach-Object {
# dump all present versions...
$list[$_] |
# sort by version descending (newest first)
Sort-Object -Property Version -Descending |
# and skip newest, returning all other
Select-Object -Skip 1
} |
# remove outdated (check whether you really don't need them anymore)
Uninstall-Module -WhatIf

PowerShell 技能连载 - 管理已安装的模块(第 1 部分)

通过 Install-Module 安装新的 PowerShell 模块时,PowerShell 会记住安装位置。因此,很容易获得通过 Install-Module 安装的模块的列表:

1
2
3
4
5
6
7
8
9
10
11
PS> Get-InstalledModule

Version Name Repository Description
------- ---- ---------- -----------
2.7.1.9 ISESteroids PSGallery Extension for PowerShell ISE 3.0 and better
2.2.0 PoSHue PSGallery Script and Control your Philips Hue Bridge, Lights, Gro...
0.14.0 platyPS PSGallery Generate PowerShell External Help files from Markdown
2.4 PSOneTools PSGallery commands taken from articles published at https://power...
1.0 QRCodeGenerator PSGallery Automatically creates QR codes as PNG images for person...
1.0 ScriptBlockLoggingAnalyzer PSGallery Functions to manage PowerShell script block logging
1.0 UserProfile PSGallery This module manages user profiles on local and remote c...

由于新版本是并行安装的,因此可以搜索不再需要的旧版本:

1
2
Get-InstalledModule |
Get-InstalledModule -AllVersions

PowerShell 技能连载 - 修复 PowerShell Gallery 的访问

The PowerShell Gallery (www.powershellgallery.com) 是查找新的 PowerShell 命令的理想场所。借助 Install-Module,您可以轻松下载并安装新的 PowerShell 模块。

但是,有时候会失败,有两个主要原因。

有时,Windows 10 自带的 PowerShellGet 模块已过时。然后,您会收到有关提示缺少参数或错误参数的异常信息。

要解决此问题,您需要手动更新 PowerShellGet。使用管理员权限运行以下行:

1
Install-Module -Name PowerShellGet -Repository PSGallery -Force

第二个常见原因:Windows 版本不支持 TLS 1.2 协议。在这种情况下,您会遇到连接问题。尝试运行以下命令:

1
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

此设置适用于当前的 PowerShell 会话。如果要保留此设置,请将该行放入您的配置文件脚本中。该路径可以在 $profile 中找到。

PowerShell 技能连载 - 创建图标

在上一个技能中,我们展示了如何微调 “Windows Terminal” 并将新的项目添加到可启动应用程序列表中。如果要为这些条目添加图标,则需要适当的图标文件。

这是一些从可执行文件中提取图标的 PowerShell 代码。您可以在 Windows Terminal 和其他地方使用生成的 ICO 文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# create output folder
$destination = "c:\icons"
mkdir $destination -ErrorAction Ignore


Add-Type -AssemblyName System.Drawing

# extract PowerShell ISE icon
$path = "$env:windir\system32\windowspowershell\v1.0\powershell_ise.exe"
$name = "$destination\ise.ico"
[System.Drawing.Icon]::ExtractAssociatedIcon($path).ToBitmap().Save($name)

# extract Visual Studio Code icon
$Path = "$env:LOCALAPPDATA\Programs\Microsoft VS Code\code.exe"
$name = "$destination\vscode.ico"
[System.Drawing.Icon]::ExtractAssociatedIcon($path).ToBitmap().Save($name)

explorer $destination

PowerShell 技能连载 - 调优 Windows Terminal

在前面的技能中,我们介绍了如何通过 Microsoft Store 在 Windows 10 上安装 “Windows Terminal”。Windows Terminal 将 PowerShell 控制台放在单独的标签页中,非常实用。

您可以通过编辑设置文件来控制选项卡下拉列表中可用的控制台类型:在 Windows Terminal 中,在标题栏中单击向下箭头按钮,然后选择“设置”。这将在关联的编辑器中打开一个 JSON 文件。如果没有与 JSON 文件关联的编辑器,则可以选择一个或使用记事本。

“配置文件”部分列出了您可以使用“向下箭头”按钮在 Windows Terminal 中打开的控制台类型。这是一个例子:

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
"profiles":
    {
        "defaults":
        {
            // Put settings here that you want to apply to all profiles.
        },
        "list":
        [
            {
                // Make changes here to the powershell.exe profile.
                "guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
                "name": "Windows PowerShell",
                "commandline": "powershell.exe",
                "hidden": false,
                "useAcrylic": true,
        "acrylicOpacity" : 0.8,
            },
            {
                // Make changes here to the cmd.exe profile.
                "guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
                "name": "Command Shell",
                "commandline": "cmd.exe",
                "hidden": false,
                "useAcrylic": true,
        "acrylicOpacity" : 0.8,
            },
            {
                "guid": "{574e775e-4f2a-5b96-ac1e-a2962a402336}",
                "hidden": false,
                "name": "PowerShell",
                "source": "Windows.Terminal.PowershellCore",
                "useAcrylic": true,
        "acrylicOpacity" : 0.8,
            },
            {
                "guid": "{2595cd9c-8f05-55ff-a1d4-93f3041ca67f}",
                "hidden": false,
                "name": "PowerShell Preview (msix)",
                "source": "Windows.Terminal.PowershellCore",
                "useAcrylic": true,
        "acrylicOpacity" : 0.8,
            },
            {
                "guid": "{b453ae62-4e3d-5e58-b989-0a998ec441b8}",
                "hidden": false,
                "name": "Azure Cloud Shell",
                "source": "Windows.Terminal.Azure",
                "useAcrylic": true,
        "acrylicOpacity" : 0.8,
            },
            {
                "guid": "{0caa0dae-35be-5f56-a8ff-afceeeaa6101}",
                "name": "Terminal As Admin",
                "commandline": "powershell.exe -command start 'C:/wt/wt.exe' -verb runas",
                "icon": "ms-appx:///Images/Square44x44Logo.targetsize-32.png",
                "hidden": false
            },
            {
                "guid": "{0ca30dae-35be-5f56-a8ff-afceeeaa6101}",
                "name": "ISE Editor",
                "commandline": "powershell.exe -command powershell_ise",
                "icon": "c:/wt/ise.ico",
                "hidden": false
            },
            {
                "guid": "{b39ac7db-ace0-4165-b312-5f2dfbbe4e4d}",
                "name": "VSCode",
                "commandline": "cmd.exe /c \"%LOCALAPPDATA%/Programs/Microsoft VS Code/code.exe\"",
                "icon": "c:/wt/vscode.ico",
                "hidden": false
            }
        ]
    }

如您所见,您可以定义任何可执行文件的路径,使用 “useAcrylic” 和 “acrylicOpacity” 等选项可以控制透明度。

看一下列表末尾的条目:它们说明了如何使用下拉菜单启动外部程序,例如编辑器(VSCode、ISE),甚至使用管理员权限打开 Windows Terminal。

诀窍是使用 “cmd.exe /c“ 或 “powershell“ 启动外部应用程序。如果直接启动外部应用程序,这将导致空白的选项卡窗口保持打开状态,直到再次关闭外部应用程序。

还要注意如何将喜欢的图标添加到列表项:使用 “icon” 并提交位图或 ico 文件。在即将发布的技巧中,我们将展示如何通过 PowerShell 代码创建此类图标文件。

如果您打算将新条目添加到列表中,请记住每个条目都需要一个唯一的 GUID。在 PowerShell 中,可以使用 New-Guid 来创建一个。

保存 JSON 文件后,修改立即生效。如果您进行的 JSON 编辑损坏了文件或引入了语法错误(例如不匹配的引号等),则 Windows Terminal 会报错。最好在编辑之前制作备份副本,并使用像 VSCode 这样的编辑器来支持 JSON 格式,并通过语法错误提示来帮助您。

PowerShell 技能连载 - 将 Windows Terminal 变成便携式应用程序

在 Windows 10 上,任何 PowerShell 用户都可以使用一个很棒的新工具:Windows Terminal。它使您可以同时使用多个 PowerShell 和其他控制台选项卡,并且可以混合使用 Windows PowerShell、PowerShell 7 和 Azure CloudShell 控制台。您可以从 Microsoft Store 安装 Windows Terminal。

与任何应用程序一样,Windows Terminal 由 Windows 管理,可以随时更新。而且它总是“按用户”安装。

如果计划在其中一个控制台中运行冗长的任务或关键业务脚本,则可能需要将该应用程序转换为仅由您自己控制的便携式应用程序。这样,多个用户也可以使用 Windows App。

以下脚本要求您已安装 Windows Terminal 应用程序,并且必须以管理员权限运行代码:

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
#requires -RunAsAdmin

# location to store portable app
$destination = 'c:\windowsterminal'


# search for installed apps...
Get-ChildItem "$env:programfiles\WindowsApps\" |
# pick Windows Terminal...
Where-Object name -like *windowsterminal* |
# find the executable...
Get-ChildItem -Filter wt.exe |
# identify executable versions...
Select-Object -ExpandProperty VersionInfo |
# sort versions...
Sort-Object -Property ProductVersion -Descending |
# pick the latest...
Select-Object -First 1 -ExpandProperty filename |
# get parent folder...
Split-Path |
# dump folder content...
Get-ChildItem |
# copy to destination folder
Copy-Item -Destination $destination -Force

# open folder
explorer $destination

# run portable app
Start-Process -FilePath "$destination\wt.exe"

PowerShell 技能连载 - 为任何用户启动 Windows 终端

在 Windows 10 上,任何 PowerShell 用户都可以使用一个很棒的新工具:Windows Terminal。它使您可以同时使用多个 PowerShell 和其他控制台选项卡,并且可以混合使用 Windows PowerShell、PowerShell 7 和 Azure Cloud Shell 控制台。您可以从 Microsoft Store 安装Windows Terminal。

由于 Windows Terminal 是一个“应用程序”,因此始终以为每个用户独立安装。只有事先为该用户安装了该应用程序,才可以通过其可执行文件 wt.exe 启动它。

启动 Windows Terminal 的另一种方法是以下命令:

1
start shell:appsFolder\Microsoft.WindowsTerminal_8wekyb3d8bbwe!App

如果此调用不能帮助您从其他用户帐户启动 Windows Terminal,那么在即将发布的技能中,我们将介绍如何将应用程序转变为不再由 Windows 管理的便携式应用程序。取而代之的是,您可以用任何用户(包括高级帐户)运行它。敬请关注。

PowerShell 技能连载 - 彻底删除 AD 对象

许多 Active Directory 对象都受到保护,无法删除。尝试删除它们时,会出现错误,从而防止您意外删除无法还原的用户帐户。

当然,这可以防止您合法删除甚至将对象移动到新的 OU。

若要确定是否防止意外删除 AD 对象,请使用以下命令:

1
Get-ADObject ‹DN of object› -Properties ProtectedFromAccidentalDeletion

要关闭保护,即在您计划移动或删除对象时,请将属性设置为 $false

1
Set-ADObject ‹DN of object› -ProtectedFromAccidentalDeletion $false

PowerShell 技能连载 - 以可点击图标的方式部署 PowerShell(第 2 部分)

在上一个技巧中,我们说明了如何在Windows资源管理器快捷方式文件中嵌入多达 4096 个字符的PowerShell代码并生成可单击的PowerShell代码。

只需右键单击链接文件并打开属性对话框,即可轻松查看嵌入的 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
33
34
35
36
37
38
39
40
41
$code = {
# place your code here (must be less than 4096 characters)
# (this example generates a battery report on notebooks
# and opens it in your default browser)
$r = "$env:temp\report.html"
powercfg /batteryreport /duration 14 /output $r
Invoke-Item -Path $r
Start-Sleep -Seconds 2
Remove-Item -Path $r
}

# turn code into a one-liner, remove comments, escape double quotes
# NOTE: this is a very simplistic conversion. Does not support block comments
# or quoted double quotes or any edgy stuff
# USE with simple staight-forward code only
$oneliner = $code.ToString().Trim().Replace('"','\"').Replace([Char[]]10,'').
Split([Char[]]13).Trim().Where{!$_.StartsWith('#')} -join ';'

# create path to a link file. It is always placed on your desktop
# and named "clickme.lnk"
$desktop = [Environment]::GetFolderPath('Desktop')
$linkpath = Join-Path -Path $desktop -ChildPath 'ClickMe.lnk'

# create a blank string of 260 chars
$blanker = " " * 260

# create a shortcut file
$com = New-Object -ComObject WScript.Shell
$shortcut = $com.CreateShortcut($linkpath)
# minimize window so PowerShell won't pop up
$shortcut.WindowStyle = 7
# use a different icon. Adjust icon index if you want
$shortcut.IconLocation = 'shell32.dll,8'
# run PowerShell
$shortcut.TargetPath = "powershell.exe"
# submit code as an argument and prepend with a blank string
# so payload is hidden in the properties dialog
$shortcut.Arguments = "$blanker-noprofile $oneliner"

# save and create the shortcut file
$shortcut.Save()

当您双击桌面上的 “clickme” 图标时,嵌入的负载代码将运行并创建电池报告,然后将其显示在默认浏览器中。

右键单击图标并选择“属性”时,将不会显示嵌入式 PowerShell 代码。该对话框仅显示powershell.exe的路径,但不显示任何参数。

这是通过在参数前面加上 260 个空白字符来实现的。快捷方式文件最多支持 4096 个字符的命令行,而 Windows 资源管理器及其对话框仅显示前 260 个字符。要查看嵌入式有效负载,用户必须使用上面的 PowerShell 代码以编程方式读取快捷方式文件并转储 arguments 属性。