PowerShell 技能连载 - 文件系统压力测试

如果您想生成一个超大文件来做压力测试,您不需要浪费时间写入大量数据到一个文件中,使它体积增大。相反,只需要设置一个期望的文件大小来占据磁盘空间即可。

以下是创建一个 1GB 测试文件的方法:

1
2
3
4
5
6
7
8
9
10
# create a test file
$path = "$env:temp\dummyFile.txt"
$file = [System.IO.File]::Create($path)

# set the file size (file uses random content)
$file.SetLength(1gb)
$file.Close()

# view file properties
Get-Item $path

PowerShell 技能连载 - 通过参数传递命令

函数参数有一个很少见的用法:用户可以传入一个输出命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Get-ProcessList
{
param
(
[string]
[ValidateSet('GridView','String')]
$OutputMode = 'String'
)

Get-Process | & "Out-$OutputMode"

}

# output as a string
Get-ProcessList -OutputMode String
# output in a grid view window
Get-ProcessList -OutputMode GridView

PowerShell 技能连载 - 处理文件编码和 BOM

当您将文本内容写入到文件时,PowerShell cmdlet 可以指定文件编码。编码决定了字符的存储方式,并且当某个字符显示乱码时,通常是由于编码不匹配造成的。

然而,有一些编码设置是无法通过 cmdlet 参数控制的。以下是一个例子。将一个进程列表保存到 CSV 文件:

1
2
3
4
$Path = "$env:temp\export.csv"

Get-Process |
Export-CSV -NoTypeInformation -UseCulture -Encoding UTF8 -Path $Path

您现在可以在 Excel 或任意文本编辑器中打开生成的 CSV 文件。当您使用 Notepad++ 打开文件时,状态栏显示编码格式为:UTF-8-BOM。

这段 PowerShell 代码以 UTF-8 编码生成文件,所以这段没有问题。BOM 代表“字节顺序标记” (Byte Order Mark)。当使用 BOM 时,将在文件的起始处增加一个特定的字节顺序标识,这样程序可以自动识别使用的编码格式。

不过,一些编辑器和数据处理系统无法处理 BOM。要移除 BOM 并使用纯文本编码,请使用类似这样的 PowerShell 代码:

1
2
3
4
5
6
function Remove-BomFromFile($OldPath, $NewPath)
{
$Content = Get-Content $OldPath -Raw
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False
[System.IO.File]::WriteAllLines($NewPath, $Content, $Utf8NoBomEncoding)
}

在上述例子中,要将 UTF-8-BOM 转化为纯 UTF-8,请运行这段代码:

1
2
3
$Path = "$env:temp\export.csv"
$NewPath = "$env:temp\export_new.csv"
Remove-BomFromFile -OldPath $Path -NewPath $NewPath

PowerShell 技能连载 - 查找嵌套的 Active Directory 成员(第 3 部分)

在前一个技能中我们演示了如何使用 ActiveDirectory 模块中的 cmdlet 来查找某个 Active Directory 用户所有直接和间接的成员。如果您想知道当前用户的成员信息,还有一个更简单(而且更快)的方法:用当前用户的 access token 来获取当前有效的组成员:

1
2
3
4
5
$groups = [System.Security.Principal.WindowsIdentity]::GetCurrent().Groups.Translate([System.Security.Principal.NTAccount])

$groups

$groups.Count

PowerShell 技能连载 - 查找嵌套的 Active Directory 成员(第 2 部分)

在前一个技能中我们演示了如何使用 ActiveDirectory 模块中的 cmdlet 来查找某个 Active Directory 用户所有直接和间接的成员。

如果您没有权限操作 ActiveDirectory 模块,PowerShell 也可以使用纯 .NET 方法来获取成员:

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
function Get-NestedGroupMember
{
param
(
[Parameter(Mandatory,ValueFromPipeline)]
[string]
$distinguishedName
)

process
{

$DomainController = $env:logonserver.Replace("\\","")
$Domain = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$DomainController")
$Searcher = New-Object System.DirectoryServices.DirectorySearcher($Domain)
$Searcher.PageSize = 1000
$Searcher.SearchScope = "subtree"
$Searcher.Filter = "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:=$distinguishedName))"
# attention: property names are case-sensitive!
$colProplist = "name","distinguishedName"
foreach ($i in $colPropList){$Searcher.PropertiesToLoad.Add($i) | Out-Null}
$all = $Searcher.FindAll()

$all.Properties | ForEach-Object {
[PSCustomObject]@{
# attention: property names on right side are case-sensitive!
Name = $_.name[0]
DN = $_.distinguishedname[0]
} }
}
}

# make sure you specify a valid distinguishedname for a user below
Get-NestedGroupMember -distinguishedName 'CN=UserName,DC=powershell,DC=local'

PowerShell 技能连载 - 查找嵌套的 Active Directory 成员(第 1 部分)

ActiveDirectory 模块(免费的 RSAT 工具的一部分)提供许多 AD cmdlet。其中一个可以读取整个直接组的成员,例如:

1
PS> Get-ADPrincipalGroupMembership  -Identity $env:username

然而,这个 cmdlet 无法列出间接组的成员,而且它还有一个 bug:在某些场景下,它只是报告“未知错误”。

这是一个简单的读取所有组成员(包括间接成员)的替代方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function Get-NestedGroupMember
{
param
(
[Parameter(Mandatory,ValueFromPipeline)]
[string]
$Identity
)

process
{
$user = Get-ADUser -Identity $Identity
$userdn = $user.DistinguishedName
$strFilter = "(member:1.2.840.113556.1.4.1941:=$userdn)"
Get-ADGroup -LDAPFilter $strFilter -ResultPageSize 1000
}
}


Get-NestedGroupMember -Identity $env:username |
Select-Object -Property Name, DistinguishedName

PowerShell 技能连载 - 进度条定时器

这是一个使用 PowerShell 进度条的简单例子。这段代码显示一个休息倒计时的进度条。只需要调整您希望暂停的秒数即可。您可以使用这个例子在班级或会议中显示休息时间:

1
2
3
4
5
6
7
8
$seconds = 60
1..$seconds |
ForEach-Object { $percent = $_ * 100 / $seconds;

Write-Progress -Activity Break -Status "$($seconds - $_) seconds remaining..." -PercentComplete $percent;

Start-Sleep -Seconds 1
}

PowerShell 技能连载 - 自动生成文档和报告(第 4 部分)

Iain Brighton 创建了一个名为 “PScribo” 的免费的 PowerShell 模块,可以快速地创建文本、HTML 或 Word 格式的文档和报告。

要使用这个模块,只需要运行这段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# https://github.com/iainbrighton/PScribo
# help about_document

# create a folder to store generated documents
$OutPath = "c:\temp\out"
$exists = Test-Path -Path $OutPath
if (!$exists) { $null = New-Item -Path $OutPath -ItemType Directory -Force }


Document 'Report' {
Paragraph -Style Heading1 "System Inventory for $env:computername"
Paragraph -Style Heading2 'BIOS Information'
Paragraph 'BIOS details:' -Bold
$bios = Get-WmiObject -Class Win32_BIOS | Out-String
Paragraph $bios.Trim()
} |
Export-Document -Path $OutPath -Format Word,Html,Text

# open the generated documents
explorer $OutPath

在前一个技能中,我们演示了如何通过将对象转换为纯文本的方式,将结果从 cmdlet 添加到文本报告:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# https://github.com/iainbrighton/PScribo
# help about_document

# create a folder to store generated documents
$OutPath = "c:\temp\out"
$exists = Test-Path -Path $OutPath
if (!$exists) { $null = New-Item -Path $OutPath -ItemType Directory -Force }


Document 'Report' {
Paragraph -Style Heading1 "System Inventory for $env:computername"
Paragraph -Style Heading2 'BIOS Information'
Paragraph 'BIOS details:' -Bold
$bios = Get-WmiObject -Class Win32_BIOS | Out-String
Paragraph $bios.Trim()
} |
Export-Document -Path $OutPath -Format Word,Html,Text

# open the generated documents
explorer $OutPath

这是很直接的方法,但是比较土。如果您希望向复杂的表格添加对象结果,请试试这种方法:

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
# https://github.com/iainbrighton/PScribo
# help about_document

# create a folder to store generated documents
$OutPath = "c:\temp\out"
$exists = Test-Path -Path $OutPath
if (!$exists) { $null = New-Item -Path $OutPath -ItemType Directory -Force }

# generate document
Document 'BIOS' {
# get an object with rich information
$info = Get-WmiObject -Class Win32_BIOS

# find out the property names that have actual information
$properties = $info | Get-Member -MemberType *property |
Select-Object -ExpandProperty Name |
Where-Object {

$info.$_ -ne $null -and $info.$_ -ne ''

} |
Sort-Object

# turn each property into a separate object
$infos = $properties | ForEach-Object {
[PSCustomObject]@{
Name = $_
Value = $info.$_
}


}

Paragraph -Style Heading1 "BIOS Information"

# generate a table with one line per property
$infos |
# select the properties to display, and the header texts to use
Table -Columns Name,Value -Headers 'Item','Content' -Width 0

} |
Export-Document -Path $OutPath -Format Word

# open the generated documents
explorer $OutPath

它的基本思想史为每个对象属性创建新的对象,然后以表格的方式显示它们。这段代码显示 BIOS 信息的详细报告。

PowerShell 技能连载 - 自动生成文档和报告(第 4 部分)

Iain Brighton 创建了一个名为 “PScribo” 的免费的 PowerShell 模块,可以快速地创建文本、HTML 或 Word 格式的文档和报告。

要使用这个模块,只需要运行这条命令:

1
Install-Module -Name PScribo -Scope CurrentUser -Force

再之前的技能中,我们介绍了如何生成动态的表格。今天,我们来学习如何根据特定的条件,例如配置错误,高亮某个单元格。

要实现这个目的,我们使用 Set-Style 将格式应用到独立的属性上。以下示例代码选择所有 StartType 的值为 AutomaticStatus 的值是 Stopped 的对象,并将 HighlightedService 应用在 Status 属性上:

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
# https://github.com/iainbrighton/PScribo
# help about_document

# create a folder to store generated documents
$OutPath = "c:\temp\out"
$exists = Test-Path -Path $OutPath
if (!$exists) { $null = New-Item -Path $OutPath -ItemType Directory -Force }

# generate document
Document 'HighlightedReport' {

# get the service data to use:
# generate the service information to use
# (requires PowerShell 5 because prior to PowerShell 5, Get-Service does not supply
# StartType - alternative: use Get-WmiObject -Class Win32_Service, and adjust
# property names)

# IMPORTANT: run this information through Select-Object to get a cloned copy
# of the original objects so that style information can be appended
$services = Get-Service |
Select-Object -Property DisplayName, Status, StartType |
Sort-Object -Property DisplayName

# write heading
Paragraph "Services ($($services.Count) Services found):"

# define style to use for highlighting
Style -Name HighlightedService -Color Red -BackgroundColor Yellow -Bold

# apply a different format to cell "Status" for all objects where
# status is "Stopped" and StartType is "Automatic"
$services |
Where { $_.Status -eq 'Stopped' -and $_.StartType -eq 'Automatic'} |
Set-Style -Property Status -Style HighlightedService

# create the table
$services |
Table -Columns DisplayName,Status,StartType -Headers 'Display Name','Status','Startup Type' -Tabs 1


} |
Export-Document -Path $OutPath -Format Word,Html,Text

# open the generated documents
explorer $OutPath

PowerShell 技能连载 - 自动生成文档和报告(第 3 部分)

Iain Brighton 创建了一个名为 “PScribo” 的免费的 PowerShell 模块,可以快速地创建文本、HTML 或 Word 格式的文档和报告。

要使用这个模块,只需要运行这条命令:

1
Install-Module -Name PScribo -Scope CurrentUser -Force

在前一个技能中,我们介绍了如何生成动态的表格。今天,我们将介绍调整表格和显示任意数据是多么容易。我们从前一个示例中取出服务列表:

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
# https://github.com/iainbrighton/PScribo
# help about_document

# create a folder to store generated documents
$OutPath = "c:\temp\out"
$exists = Test-Path -Path $OutPath
if (!$exists) { $null = New-Item -Path $OutPath -ItemType Directory -Force }

# generate document
Document 'ServiceReport' {
# generate the service information to use
# (requires PowerShell 5 because prior to PowerShell 5, Get-Service does not supply
# StartType - alternative: use Get-WmiObject -Class Win32_Service, and adjust
# property names)
$services = Get-Service | Select-Object -Property DisplayName, Status, StartType

Paragraph -Style Heading1 "System Inventory for $env:computername"
Paragraph -Style Heading2 "Services ($($services.Count) Services found):"

# generate a table with one line per service
$services |
# select the properties to display, and the header texts to use
Table -Columns DisplayName, Status, StartType -Headers 'Service Name','Current State','Startup Type' -Width 0

} |
Export-Document -Path $OutPath -Format Word,Html,Text

# open the generated documents
explorer $OutPath

只需要做少许调整,示例代码将返回所有 ad 用户(假设您安装了 ActiveDirectory 模块并且能操作 AD):

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
# https://github.com/iainbrighton/PScribo
# help about_document

# create a folder to store generated documents
$OutPath = "c:\temp\out"
$exists = Test-Path -Path $OutPath
if (!$exists) { $null = New-Item -Path $OutPath -ItemType Directory -Force }

# generate document
Document 'ADUser' {
# get 40 AD user to illustrate
$user = Get-ADUser -Filter * -ResultSetSize 40 -Properties mail |
Select-Object -Property Name, mail, SID

Paragraph -Style Heading1 "AD User Liste"

# generate a table with one line per user
$user |
# select the properties to display, and the header texts to use
Table -Columns Name, mail, SID -Headers 'Employee','Email','SID' -Width 0

} |
Export-Document -Path $OutPath -Format Word

# open the generated documents
explorer $OutPath