PowerShell 技能连载 - 分割文本行(第 1 部分)

有时,您需要逐行处理多行文本。下面是一个多行字符串的示例:

1
2
3
4
5
6
7
8
9
10
11
# working with 1-dimensional input

# $data is a single string
$data = @'
Server1
Server2
Cluster4
'@

$data.GetType().FullName
$data.Count

将文本拆分为单独的行的一种有效方法是使用带有正则表达式的 -split 运算符,该表达式可以处理各种依赖于平台的行终止符:

1
2
3
4
5
6
7
8
9
10
# split the string in individual lines
# $array is an array with individual lines now

$regex = '[\r\n]{1,}'
$array = $data -split $regex

$array.GetType().FullName
$array.Count

$array

以下是您在脚本中遇到的 $regex 中的正则表达式的一些替代方案:

分隔用的正则表达式 说明
/r 类似于“回车”(ASCII 13)。如果操作系统不是用该字符作为换行符,则分割将会失败。如果操作系统使用该字符加上“换行”(ASCII 10),那么多出来的不可见的换行符会破坏字符串。
/n 类似上面的情况,只是相反。
[\r\n]+ 与上面的示例代码相同。如果有一个或多个字符,PowerShell 会在两个字符处拆分。这样,CR、LF 或 CRLF、LFCR 在拆分时都被删除。但是,多个连续的新行也将全部删除:CRCRCR 或 CRLFCRLF。
(\r\n \r

如果您从文本文件中读取文本,Get-Content 会自动将文本拆分为行。要将整个文本内容作为单个字符串读取,则需要添加 -Raw 参数。

PowerShell 技能连载 - 截屏

借助 System.Windows.Forms 中的类型,PowerShell 可以轻松捕获屏幕并将屏幕截图保存到文件中。下面的代码捕获整个虚拟屏幕,将屏幕截图保存到文件中,然后在相关程序中打开位图文件(如果有):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$Path = "$Env:temp\screenshot.bmp"
Add-Type -AssemblyName System.Windows.Forms

$screen = [System.Windows.Forms.SystemInformation]::VirtualScreen
$width = $screen.Width
$height = $screen.Height
$left = $screen.Left
$top = $screen.Top
$bitmap = [System.Drawing.Bitmap]::new($width, $height)
$MyDrawing = [System.Drawing.Graphics]::FromImage($bitmap)
$MyDrawing.CopyFromScreen($left, $top, 0, 0, $bitmap.Size)

$bitmap.Save($Path)
Start-Process -FilePath $Path

PowerShell 技能连载 - 禁用本地的 Guest 账户

Windows 自带一个名为 “Guest” 的内置帐户。由于此帐户很少使用,最好将它禁用。否则,它的广为人知的名字可能会成为攻击者的目标。

由于帐户名称是本地化的并且可能因文化而略有不同,因此要识别帐户,请使用其 SID:

1
2
3
4
5
PS> Get-Localuser | Where-Object Sid -like 'S-1-5-*-501'

Name Enabled Description
---- ------- -----------
Guest False Built-in account for guest access to the computer/domain

如果该帐户尚未禁用(请查看 ““Enabled”“ 属性),请使用提升权限的 PowerShell 和 Disable-LocalUser cmdlet 禁用该帐户。

PowerShell 技能连载 - 重命名本地管理员账户

出于安全原因,您可能需要考虑重命名内置的本地管理员帐户。这个账户权限很大,它的名字很容易猜到,所以它是攻击者的常用载体。在重命名此帐户之前,请确保您了解后果:

  • 该账户仍能继续工作,但您现在需要使用新分配的名称来登录该帐户。确保没有使用旧的默认名称的自动登录过程
  • 重命名帐户不会更改其 SID,因此老练的攻击者仍然可以使用其众所周知的 SID 锁定此帐户

要重命名内置 Administrator 帐户(或任何其他本地帐户),请以管理员权限启动 PowerShell,然后运行以下代码:

1
PS> Rename-LocalUser -Name "Administrator" -NewName "TobiasA"

要使用该帐户登录,请使用新分配的名称。通过使用账户的众所周知的 SID,即使您不知道其名称,您仍然可以识别重命名的帐户:

1
2
3
4
5
PS> Get-Localuser | Where-Object Sid -like 'S-1-5-*-500'

Name Enabled Description
---- ------- -----------
TobiasA False Built-in account for administering the computer/domain

PowerShell 技能连载 - 识别本地管理员组

内置管理员组的任何成员都可以访问广泛的权限,因此检查该组的成员可以成为安全审核的一部分。虽然 “Administrators” 组默认存在,但其名称可能因文化而异,因为它是本地化的。例如,在德国系统中,该组称为 “Administratoren”。

要访问用户组,而无论文化和命名如何变化,请使用其 SID,它始终为 “S-1-5-32-544”:

1
2
3
4
5
PS> Get-LocalGroup -SID S-1-5-32-544

Name Description
---- -----------
Administrators Administrators have complete and unrestricted access to the...

同样,要转储具有管理员权限的用户和组列表,请使用 SID 而不是组名:

1
PS> Get-LocalGroupMember -SID S-1-5-32-544

PowerShell 技能连载 - 识别本地管理员帐户

Windows 计算机上有一些默认帐户,例如本地 “Administrator” 帐户。虽然默认情况下此帐户存在,但其名称可以因文化而异,并且其名称也可以重命名。

要始终识别本地管理员帐户而不管其名称如何,请按 SID(安全标识符)搜索本地帐户。本地管理员帐户 SID 始终以 “S-1-5-“ 开头并使用 RID “-500”:

1
2
3
4
5
PS> Get-Localuser | Where-Object Sid -like 'S-1-5-*-500'

Name Enabled Description
---- ------- -----------
Administrator False Built-in account for administering the computer/domain

PowerShell 技能连载 - 识别连上的 Domain

确定您连上的域名称的一种快速方法是 WMI:

1
2
3
4
PS> Get-CimInstance -ClassName Win32_NTDomain

DomainName DnsForestName DomainControllerName
---------- ------------- --------------------

如果您未连接到域,则结果是一个空对象。

PowerShell 技能连载 - 简单的内置密码生成器

.NET System.Web 程序集中有一个隐藏的功能,它可以让您立即创建任意长度的随机密码:

1
2
3
4
5
6
7
8
9
10
# total password length
$Length = 10

# number of non-alpha-chars
$NonChar = 3

Add-Type -AssemblyName 'System.Web'
$password = [System.Web.Security.Membership]::GeneratePassword($Length,$NonChar)

"Your password: $password"

PowerShell 技能连载 - Creating Dummy Test Files

If you need to test file system load, test failover clusters, or need large dummy files otherwise, rather than creating new files and slowly filling them with random data, try this:

$filepath = "$env:temp\testfile.txt"
$sizeBytes = 5.75MB

$file = [System.IO.File]::Create($filepath)
$file.SetLength($sizeBytes)
$file.Close()
$file.Dispose()

# show dummy file in Windows Explorer
explorer /select,$filepath

This code creates dummy files of any size in a snap and can be used to quickly create storage load. Just don’t forget to delete these files after use.

PowerShell 技能连载 - 从网站读取 HTTP 消息头

当您导航到一个网页时,您的浏览器会静默地接收 HTTP 标头中的元信息,而这些元信息通常是不可见的。

要显示任何网站的 HTTP 消息头,请尝试以下操作:

1
2
3
# replace URL with any web page you like:
$url = 'www.tagesschau.de'
(Invoke-WebRequest -Method Head -Uri $url -UseBasicParsing).RawContent

诀窍是使用 -Method 参数并提交 Head 值来获取消息头而不是网页内容。

结果类似于:

HTTP/1.1 200 OK
Connection: keep-alive
Access-Control-Allow-Origin: *
Cache-Control: max-age=14
Content-Type: text/html; charset=utf-8
Date: Tue, 10 Aug 2021 12:06:37 GMT

The header info returned by a web page can vary greatly. When you replace the URL in above example with ‘www.google.de’, for example, you see many more instructions being sent to your browser, and you can actually “see” how the web page instructs your browser to set new cookies – so you can check whether the web page sets cookies before asking for consent or not:
网页返回的标题信息可能会有很大差异。例如,当您将上面示例中的 URL 替换为 “www.google.de“ 时,您会看到更多的指令被发送到您的浏览器,您实际上可以“看到”网页如何指示您的浏览器设置新的 cookie——因此您可以在征求同意之前检查网页是否设置了 cookie:

HTTP/1.1 200 OK
X-XSS-Protection: 0
X-Frame-Options: SAMEORIGIN
Transfer-Encoding: chunked
Cache-Control: private
Content-Type: text/html; charset=UTF-8
Date: Tue, 10 Aug 2021 12:07:06 GMT
Expires: Tue, 10 Aug 2021 12:07:06 GMT
P3P: CP="This is not a P3P policy! See g.co/p3phelp for more info."
Set-Cookie: NID=221=C8RdXG_2bB_MwOG33_lS0hx3P5TF5_vaamoT0xj3yKgZPzCjr_g70NvJXkhenV_GMt1TYYU6XwmNOtlkRKRADiXgYJWWYp671M3DFL8DCxM_J1Cl01r39-jfA7sIxu1C
-0B7CHI-8WfXj5IGZ5dHtRxndNA84cpQov5phLhi7l8; expires=Wed, 09-Feb-2022 12:07:06 GMT; path=/; domain=.google.de; HttpOnly
Server: gws

如果您愿意,您也可以以表格形式获取消息头 —— 只需将 RawContent 替换为 Headers

1
2
3
# replace URL with any web page you like:
$url = 'www.google.de'
(Invoke-WebRequest -Method Head -Uri $url -UseBasicParsing).Headers
PowerShell 技术 QQ 群