PowerShell 技能连载 - 移除 Windows 10 应用

Windows 10 预装了一系列应用程序。幸运的是,您可以用 PowerShell 来移除您不想要的程序。当然,需要管理员权限。

要查看安装了哪些应用程序,请运行这段代码:

Get-AppxPackage -User $env:USERNAME

这将列出所有用您自己的用户账户安装的应用程序。要移除应用程序,请使用 PackageFullName,并且将它传给 Remove-AppxPackage 命令。请在更改之前备份您的系统,而且风险自负。多数应用程序并不是必须的。

PowerShell 技能连载 - 修正远程发送者信息

如果您使用 Invoke-Command 来远程执行 PowerShell 代码,您可能会注意到 PowerShell 远程操作会添加一个新的 PSComputerName 属性用来表示数据的来源。

这段代码将获取名为 dc-01 的机器的进程列表。PSComputerName 属性指明了源计算机名。当您使用多于一台电脑时十分有用。

#requires -Version 2
$code = {
  Get-Process
}

Invoke-Command -ScriptBlock $code -ComputerName dc-01

然而,如果您将结果用管道输出到 Out-GridViewPSComputerName 属性消失了。

作为一个变通办法,当您将结果输出到 Select-Object 命令时,PSComputerName 属性将会在网格视图窗口中正确地显示。

#requires -Version 2
$code = {
  Get-Process |
    Select-Object -Property Name, ID, Handles, CPU
}

Invoke-Command -ScriptBlock $code -ComputerName dc-01 |
  Out-GridView

PowerShell 技能连载 - 设置新的 Windows 注册所有者

这一小段代码将提示输入新的注册所有者名,然后将更新 Windows 注册表中的值。请注意需要管理员权限。

#requires -RunAsAdministrator


$NewName = Read-Host -Prompt 'Enter New Registered Windows Owner'

Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name RegisteredOwner -Value $NewName -Type String

这也是一个更改 Windows 注册表的模板代码。

PowerShell 技能连载 - 下载文件

Invoke-WebRequest 可以从 internet 下载文件。这个例子将下载一个 33MB 的 NASA 公开视频到您的计算机上,然后用您计算机上 WMV 视频文件的关联应用打开它:

#requires -Version 3

$Video = 'http://s3.amazonaws.com/akamai.netstorage/HD_downloads/BEAMextract_final_revB.wmv'
$Destination = "$env:temp\nasavideo1.wmv"
Invoke-WebRequest -Uri $Video -OutFile $Destination -UseBasicParsing

Invoke-Item -Path $Destination

PowerShell 技能连载 - 将哈希表用作条件化的代码库

脚本中平时经常需要检测一个文件夹是否存在,如果不存在则创建:

#requires -Version 1

$path = 'c:\testfolder'
$exists = Test-Path -Path $path

if ($exists)
{
  $null = New-Item -Path $path -ItemType Directory
  Write-Warning -Message 'Folder created'
}
else
{
  Write-Warning -Message 'Folder already present'
}

以下是一种很不常见的方法,以一种不同的概念实现相同的功能:

#requires -Version 1

$Creator = @{
  $true = { Write-Warning 'Folder already present'}
  $false = {$null = New-Item -Path $Path -ItemType Directory
            Write-Warning 'Folder created'}
}


$Path = 'c:\testfolder2'
& $Creator[(Test-Path $Path)]

实际上,这段脚本用了一个哈希表($Creator))来存储两个脚本块,而它的键是 $true$false

现在,根据文件夹存在与否,哈希表将返回合适的脚本块,接下来被 &(调用)操作符执行。

哈希表用这种方式来模拟从句。

PowerShell 技能连载 - 为什么 Invoke-Expression 是邪恶的

Invoke-Expression 接受任何字符串输入并将它视为 PowerShell 代码。通过这种方式,您可以动态地创建代码,并执行它。

Invoke-Expression 是一个非常危险的命令,因为不仅您可以创建动态的代码。恶意的脚本可以隐藏它的邪恶目的,例如通过 web 站点下载代码。

以下是一个安全并有趣的例子,演示了如何从下载到执行一段代码:

#requires -Version 3

Invoke-Expression -Command (Invoke-WebRequest -Uri 'http://bit.ly/e0Mw9w' -UseBasicParsing).Content

如果您不希望发生意外,这行代码可以帮您预览将会发生什么。请在 PowerShell ISE 中运行这段代码。它将显示从 internet 下载的 PowerShell 代码,而不是立即执行它:

#requires -Version 3

$file = $psise.CurrentPowerShellTab.Files.Add()

$file.Editor.text = (Invoke-WebRequest -Uri 'http://bit.ly/e0Mw9w' -UseBasicParsing).Content

PowerShell 技能连载 - 访问网页内容

从 PowerShell 3.0 开始,Invoke-WebRequest 命令可以轻松地下载网页内容。例如这个例子可以从 www.powertheshell.com 获取所有链接:

#requires -Version 3

$url = 'http://www.powertheshell.com'
$page = Invoke-WebRequest -Uri $url
$page.Links

您也可以用这种方式获取原始的 HTML 内容:

#requires -Version 3

$url = 'http://www.powertheshell.com'
$page = Invoke-WebRequest -Uri $url
$page.RawContent

当您用这种方法处理其它 URL 时,您可能偶尔会遇到弹出一个安全警告框,提示需要存储 cookie 的权限。要禁止这些对话框出现并静默执行命令,请使用 -UseBasicParsing 参数。

PowerShell 技能连载 - 分析 svchost 进程

有时候,您会在任务管理器或 Get-Process 输出中看到一系列名为“svchost”的进程。每个“svchost”进程中运行着一个或多个 Windows 服务。

要更好地理解这些进程后隐藏着哪些服务,您可以使用这样的代码:

#requires -Version 2
# Hash table defines two keys:
# Name and Expression
# they can be used with Select-Object
# to produce "calculated" properties
$Service = @{
  Name = 'Service'
  Expression = {
    # if the process is "svchost"...
    if ($_.Name -eq 'svchost')
    {
      # ...find out the current process ID...
      $processID = $_.ID
      # ...and look up the services attached to it
      ($serviceList.$processID).Name -join ', '
    }
  }
}

# create a service lookup table with ProcessID as a key
$serviceList = Get-WmiObject -Class Win32_Service |
Group-Object -Property ProcessID -AsString -AsHashTable

# get all running processes...
Get-Process |
# add the new calculated column defined in $Service...
Select-Object -Property Name, ID, CPU, $Service |
# and output results to a grid view Window
Out-GridView

当您运行这段代码时,您会见到当前运行中的进程列表。当进程名是“svchost”时,您会在新的“Service”列中查看到服务名。

PowerShell 技能连载 - 用 ProcessID 定位服务

Group-Object 是一个创建查询表的很好的命令。如果您希望用进程 ID 来定位一个 Windows 服务,以下是实现方法:

$serviceList = Get-WmiObject -Class Win32_Service | Group-Object -Property ProcessID -AsString -AsHashTable

一旦变量被赋值之后,只需要用进程 ID 作为属性即可:

PS> $serviceList.672


ExitCode  : 0
Name      : WSearch
ProcessId : 672
StartMode : Auto
State     : Running
Status    : OK

PowerShell 技能连载 - 创建真实的类

PowerShell 5.0 开始引入了类的概念,不过您也可以在 PowerShell 的其它版本中使用自定义类。只需要用 C# 代码来定义真正的类,然后用 Add-Type 来编译这些类。

以下是一个创建一个名为“myClass”,包含三个属性的新类。PowerShell 接下来可以用 New-Object 命令创建对象。

$code = '
    using System;
    public class myClass
    {
        public bool Enabled { get; set; }
        public string Name { get; set; }
        public DateTime Time { get; set; }


    }

'

Add-Type -TypeDefinition $code
$instance = New-Object -TypeName myClass
$instance.Enabled = $true
$instance.Time = Get-Date
$instance.Name = $env:username
$instance

为什么需要这么做呢?自定义的类可以包含来自多个来源的信息,而且您可以使用 C# 的各种复杂特性来定义您的类,包括方法、动态和静态成员等。

显然,拥有一些技术背景的开发人员对这种技术最感兴趣。