PowerShell 技能连载 - 理解脚本块日志(第 6 部分)
这是关于 PowerShell 脚本块日志的迷你系列的第 6 部分。该是时候介绍最后的部分了:当您执行一段非常大的 PowerShell 脚本时,它们是分块记录的。还缺少的部分是整理代码片段的逻辑:
1 | function Get-LoggedCode |
本质上,这个函数检查该脚本是否是由多段组成。如果是,它将代码添加到 $code
中,直到当前块等于 最后一块。就是这么简单。
这是关于 PowerShell 脚本块日志的迷你系列的第 6 部分。该是时候介绍最后的部分了:当您执行一段非常大的 PowerShell 脚本时,它们是分块记录的。还缺少的部分是整理代码片段的逻辑:
1 | function Get-LoggedCode |
本质上,这个函数检查该脚本是否是由多段组成。如果是,它将代码添加到 $code
中,直到当前块等于 最后一块。就是这么简单。
这是关于 PowerShell 脚本块日志的迷你系列的第 5 部分。我们已经几乎达到目标了,缺少的是一个更好的方式来读取记录的代码。在我们之前的方法中,执行代码的用户收到一个晦涩的 SID 而不是一个清晰的名称。以下是一个将用户 SID 转为真实名称的函数,并且使用智能缓存来加速 SID 的查询过程:
1 | function Get-LoggedCode |
这是关于 PowerShell 脚本块日志的迷你系列的第 4 部分。到目前为止,您已经了解了如何读取记录的 PowerShell 代码,以及如何打开详细模式。打开详细模式后,机器上运行的所有 PowerShell 代码都会记录下来,所以会产生大量的数据。为了不覆盖旧的日志数据,您需要增加日志文件的尺寸。以下是操作方法:
1 | function Set-SBLLogSize |
要将日志文件的尺寸从缺省的 15MB 增加到 100MB,请运行以下代码(需要管理员特权):
1 | PS> Set-SBLLogSize -MaxSizeMB 100 |
这是关于 PowerShell 脚本块日志的迷你系列的第 2 部分。缺省情况下,只有被认为有潜在威胁的命令会记录日志。当启用了详细日志后,由所有用户执行的所有执行代码都会被记录。
要启用详细模式,您需要管理员特权。以下是一个启用详细日志的函数:
1 | function Enable-VerboseLogging |
当您运行 Enable-VerboseLogging
之后,所有 PowerShell 代码将会记录到日志中。您可以使用我们之前介绍的方式之一来读取记录的代码,例如我们的 Get-LoggedCode
:
1 | function Get-LoggedCode |
请注意只有改变日志设置需要管理员特权。而所有用户都可以读取记录的数据。
如果您希望禁止详细模式并且返回到缺省的设置,请使用这个函数:
1 | function Get-LoggedCode |
请注意即便详细脚本日志被关闭,PowerShell 将仍会记录和安全相关的代码。
这是关于 PowerShell 脚本块日志的迷你系列的第 2 部分。今天,我们将会再次读取脚本块日志的记录。但是这次我们将以更加面向对象的方式读取日志数据:
1 | function Get-LoggedCode |
当您运行这段代码时,您将得到一个新的名为 Get-LoggedCode
的命令。当您执行它时,它将返回类似这样的对象:
1 | Time : 25.05.2018 10:57:36 |
在我们的代码中,我们添加了 Select-Object
来读取整个日志,而不是最后一条日志。这里,我们得到我们刚刚执行的代码。您机器上的执行情况可能有所不同,原因如下:
缺省情况下,脚本快日志只记录“安全相关”(在返回的数据中,级别为 “Warning”)的代码。PowerShell 内部判断哪些代码是和安全相关的。在明天的技能中,我们将会介绍如何启用 “Verbose” 模式。当该模式打开时,所有代码都会被记录,所以日志文件的体积会增长得很快。以下是缺省设置 (“Warning”) 日志和详细日志的数量对比(从测试机器中提取):
1 | PS> Get-LoggedCode | Group-Object Level |
请注意:由于日志的体积非常大,所以长的代码被分成多块。”IsMultiPart
“、”PartCurrent
“ 和 “PartTotal
“ 属性可以提供这方面的有用信息。
从 PowerShell 5 开始,PowerShell 引擎开始记录执行的命令和脚本块。缺省情况下,只有被认为有潜在威胁的命令会记录日志。当启用了详细日志后,由所有用户执行的所有执行代码都会被记录。
这是一个介绍脚本块日志的迷你系列的第一部分。今天,我们只是学习以最基础的方式使用脚本块日志。一行代码就够了:
1 | $logInfo = @{ ProviderName="Microsoft-Windows-PowerShell"; Id = 4104 } |
这将从 “Microsoft-Windows-PowerShell” 的日志(它包含代码日志)中读取所有 ID 为 4104 的事件。请注意 PowerShell Core 也记录日志,但是使用的是一个不同的日志文件。
您现在可以类似这样获取大量的数据:
Creating Scriptblock text (1 of 1):
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Bypass
ScriptBlock ID: aeb85bcb-98be-42d0-b695-fbbb975ec5d2
Path:
如果 Path
为空,则说明该命令以交互的方式执行。否则,在这里可以查看到脚本的路径。
如果您没有获取到任何信息,请考虑以下可能性:
以下代码是和安全相关的,当您执行它时,您将会从后续的日志中读取到这行代码:
1 | PS> Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass -Force |
如果您需要数字前面添加前导零,例如对于服务器名,以下是两种实现方式。第一,您可以将数字转换为字符串,然后用 PadLeft()
函数将字符串填充到指定的长度:
1 | $number = 76 |
如果您希望显示一个带有按钮,可供用户点击的消息框,请试试这个函数:
1 | function Show-MessageBox |
以下是它的使用方法:
1 | PS> Show-MessageBox -Text 'Do you want to reboot now?' -Caption Reboot -Button YesNoCancel -Icon Exclamatio |
如果您想弹出一个快速而粗糙的输入框,提示用户输入数据,您可以通过 Microsoft Visual Basic 并且“借用”它的 InputBox 控件:
1 | Add-Type -AssemblyName Microsoft.VisualBasic |
但是请注意,这种方法有一些局限性:该输入框可能在您的 PowerShell 窗口之下打开,而且在高分辨率屏中,它的缩放可能不正确。
PowerShell 有许多读取文本文件的方法,它们的性能差异很大。请自己确认一下。以下例子演示了不同的实践,并测量执行的时间。请确保例子中的路径实际存在。如果文件不存在,请选择一个大文件来测试。
1 | # make sure this file exists, or else |