PowerShell 技能连载 - 从德国媒体数据库下载视频

在德国,有一些公开的媒体数据库,里面有公共站点发布的电视内容。只需要用一小段 PowerShell 代码就可以解析 JSON 数据,在一个列表中显示电视节目,并使你能够选择某项来下载。

请注意包含下载链接的 JSON 文件非常大,所以需要过一段时间才能显示出视频列表。

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
#requires -Version 3.0

# here is the list of download URLs - get it and
# convert the JSON format
$url = 'http://www.mediathekdirekt.de/good.json'
$web = Invoke-WebRequest -Uri $url -UseBasicParsing
$videos = $web.Content | ConvertFrom-Json

# get all videos, create a nice title to display,
# and attach the original data to each entry
$videos |
ForEach-Object {
$title = '{0} - {1}' -f $_[2], $_[5]
$title | Add-Member -MemberType NoteProperty -Name Data -Value $_ -PassThru
} |
Sort-Object |
Out-GridView -Title 'Video' -OutputMode Multiple |
ForEach-Object {
# get the actual download info from the selected videos
# and do the download
$url = $_.Data[6]
$filename = Split-Path -Path $url -Leaf
# videos are saved into your TEMP folder unless you
# specify a different folder below
$filepath = Join-Path -Path $env:temp -ChildPath $filename
Invoke-WebRequest -Uri $url -OutFile $filepath -UseBasicParsing
Invoke-Item -Path $filepath
}

PowerShell 技能连载 - 翻译错误记录

Whenever PowerShell records an error, it wraps it in an Error Record object. Here is a function that takes such an error record and extracts the useful information:
当 PowerShell 记录一个错误时,它将错误信息包装在一个 Error Record 对象中。以下是一个处理这种错误记录并解析有用信息的函数:

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
#requires -Version 3.0
function Get-ErrorDetail
{
param
(
[Parameter(Mandatory,ValueFromPipeline)]
$e
)
process
{
if ($e -is [Management.Automation.ErrorRecord])
{
[PSCustomObject]@{
Reason = $e.CategoryInfo.Reason
Exception = $e.Exception.Message
Target = $e.CategoryInfo.TargetName
Script = $e.InvocationInfo.ScriptName
Line = $e.InvocationInfo.ScriptLineNumber
Column = $e.InvocationInfo.OffsetInLine
Datum = Get-Date
User = $env:USERNAME
}
}
}
}

如果您想知道最后的错误信息是什么,请试试这个:

1
2
3
PS C:\> $error | Get-ErrorDetail | Out-GridView

PS C:\>

或者,您现在可以简单地命令一个 cmdlet 缓存它的错误信息,并在晚些时候处理它们。这个例子递归地在 Windows 文件夹中搜索 PowerShell 脚本。您可以获取结果,以及搜索时发生的所有错误的详细信息:

1
2
3
$files = Get-ChildItem -Path c:\Windows -Filter *.ps1 -Recurse -ErrorAction SilentlyContinue -ErrorVariable myErrors

$myErrors| Get-ErrorDetail | Out-GridView

PowerShell 技能连载 - 用 Out-GridView 启用 AD 用户

有些时候在 PowerShell 中只需要几行代码就可以创造出很有用的支持工具。以下是一个显示所有禁用的 AD 用户的例子。您可以选择一个(或按住 CTRL 键选择多个),然后点击 OK,这些用户将会被启用:

1
2
3
4
5
#requires -Version 3.0 -Modules ActiveDirectory
Search-ADAccount -AccountDisabled |
Out-GridView -Title 'Who should be enabled?' -OutputMode Multiple |
# remove -WhatIf to actually enable accounts
Enable-ADAccount -WhatIf

PowerShell 技能连载 - 将 AD 用户转为哈希表

有些时候从一个指定的 AD 用户读取所有属性到一个哈希表中十分有用。通过这种方法,您可以编辑他们,并使用 Set-ADUser 和它的 -Add-Replace 参数将他们应用于另一个用户账户。

以下是将所有 AD 用户属性读到一个哈希表中的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#requires -Version 3.0 -Modules ActiveDirectory

$blacklist = 'SID', 'LastLogonDate', 'SAMAccountName'

$user = Get-ADUser -Identity NAMEOFUSER -Properties *
$name = $user | Get-Member -MemberType *property | Select-Object -ExpandProperty Name

$hash = [Ordered]@{}
$name |
Sort-Object |
Where-Object {
$_ -notin $blacklist
} |
ForEach-Object {
$hash[$_] = $user.$_
}

请注意 $blacklist 的使用:这个列表可以包含任何希望排除的属性名。

PowerShell 技能连载 - 克隆文件夹结构(含 NTFS 权限) – 第二部分

在前一个技能中我们演示了 Get-FolderStructureWithPermission 如何以结构化的形式记录并创建一个包含所有嵌套文件夹的清单,包含它们各自的 NTFS 安全设置。结果可以保存到一个变量中,或用 Export-Csv 序列化后保存到磁盘中。

今天我们演示第二部分:当您拥有一个指定文件夹结构的信息之后,可以使用这个 Set-FolderStructureWithPermission。它输入一个要克隆其结构的文件夹路径,加上通过 Get-FolderStructureWithPermission 获得的结构信息:

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

function Set-FolderStructureWithPermission
{
param
(
[String]
[Parameter(Mandatory)]
$Path,

[Object[]]
$folderInfo
)

$folderInfo | ForEach-Object {
$relativePath = $_.Path
$sddl = $_.SDDL

$newPath = Join-Path -Path $Path -ChildPath $relativePath
$exists = Test-Path -Path $newPath
if ($exists -eq $false)
{
$null=New-Item -Path $newPath -ItemType Directory -Force
}
$sd = Get-Acl -Path $newPath
$sd.SetSecurityDescriptorSddlForm($sddl)
Set-Acl -Path $newPath -AclObject $sd
}
}

由于设置 NTFS 权限的需要,这个函数需要管理员特权才能运行。

免责声明:这里呈现的所有代码仅供学习使用。由于我们没有投入大量精力去测试它,所以没有任何保障,而且它并不是生产准备就绪的代码。您有责任对这段代码进行测试,并决定它是否完美符合您的需要。

一个典型的用例是克隆一个现有的文件夹结构:

1
2
3
# clone user profile
$infos = Get-FolderStructureWithPermission -Path $home
Set-FolderStructureWithPermission -Path c:\CloneHere -folderInfo $infos

PowerShell 技能连载 - 克隆文件夹结构(含 NTFS 权限) – 第一部分

有些时候您需要重新创建一个嵌套的文件夹结构,并且希望克隆 NTFS 权限。今天我们我们专注第一个步骤:记录一个已有的文件夹结构,包括 SDDL 格式的 NTFS 权限。

我们可以用 Get-FolderStructureWithPermission 函数实现这个任务。它输入一个已存在文件夹的路径,并返回所有子文件夹,包括 SDDL 格式的 NTFS 权限:

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
function Get-FolderStructureWithPermission
{
param
(
[String]
[Parameter(Mandatory)]
$Path
)

if ((Test-Path -Path $Path -PathType Container) -eq $false)
{
throw "$Path does not exist or is no directory!"
}

Get-ChildItem -Path $Path -Recurse -Directory |
ForEach-Object {
$sd = Get-Acl -Path $_.FullName
$sddl = $sd.GetSecurityDescriptorSddlForm('all')


[PSCustomObject]@{
Path = $_.FullName.Substring($Path.Length)
SDDL = $sddl
}

}
}

您可以将结果通过管道输出到 Out-GridView,或将它保存到一个变量,或用 Export-Csv 将它写到磁盘中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
PS C:\> Get-FolderStructureWithPermission -Path $home | Format-List


Path : \.dnx
SDDL : O:S-1-5-21-2012478179-265285931-690539891-1001G:S-1-5-21-2012478179-265285931-690539891-1001D:(A;OICIID;FA;;;SY)(A;OI
CIID;FA;;;BA)(A;OICIID;FA;;;S-1-5-21-2012478179-265285931-690539891-1001)

Path : \.plaster
SDDL : O:S-1-5-21-2012478179-265285931-690539891-1001G:S-1-5-21-2012478179-265285931-690539891-1001D:(A;OICIID;FA;;;SY)(A;OI
CIID;FA;;;BA)(A;OICIID;FA;;;S-1-5-21-2012478179-265285931-690539891-1001)

Path : \.vscode
SDDL : O:S-1-5-21-2012478179-265285931-690539891-1001G:S-1-5-21-2012478179-265285931-690539891-1001D:(A;OICIID;FA;;;SY)(A;OI
CIID;FA;;;BA)(A;OICIID;FA;;;S-1-5-21-2012478179-265285931-690539891-1001)

Path : \.vscode-insiders
SDDL : O:S-1-5-21-2012478179-265285931-690539891-1001G:S-1-5-21-2012478179-265285931-690539891-1001D:(A;OICIID;FA;;;SY)(A;OI
CIID;FA;;;BA)(A;OICIID;FA;;;S-1-5-21-2012478179-265285931-690539891-1001)

Path : \3D Objects
SDDL : O:S-1-5-21-2012478179-265285931-690539891-1001G:S-1-5-21-2012478179-265285931-690539891-1001D:(A;OICIID;FA;;;SY)(A;OI
CIID;FA;;;BA)(A;OICIID;FA;;;S-1-5-21-2012478179-265285931-690539891-1001)

...

免责声明:这里呈现的所有代码仅供学习使用。由于我们没有投入大量精力去测试它,所以没有任何保障,而且它并不是生产准备就绪的代码。您有责任对这段代码进行测试,并决定它是否完美符合您的需要。

PowerShell 技能连载 - 评估 Exit Code(也叫做 Error Level – 第三部分)

在 PowerShell 中运行控制台应用程序的迷你系列的第三部分中,有一个小课题:如何独立于 PowerShell 运行一个控制台应用程序,并且当它执行完成后得到通知,并且获取它的 exit code?

以下是实现方法:以下代码在一个独立(隐藏)的窗口中运行 ping.exe。PowerShell 继续运行并且可以执行任何其它操作。在这个例子中,它在 ping.exe 正忙于 ping 一个主机名的同时打出一系列“点”号。

当 exe 执行完成时,这段代码能获取进程的 ExitCode 信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$hostname = 'powershellmagazine.com'
# run the console-based application ASYNCHRONOUSLY in its own
# window (PowerShell continues) and return the
# process object (-PassThru)
# Hide the new window (you can also show it if you want)
$process = Start-Process -FilePath ping -ArgumentList "$hostname -n 4 -w 2000" -WindowStyle Hidden -PassThru

# wait for the process to complete, and meanwhile
# display some dots to indicate progress:
do
{
Write-Host '.' -NoNewline
Start-Sleep -Milliseconds 300
} until ($process.HasExited)
Write-Host

# the Error Level information is then found in ExitCode:
$IsOnline = $process.ExitCode -eq 0
$IsOnline

PowerShell 技能连载 - 评估 Exit Code(也叫做 Error Level – 第二部分)

当您直接启动一个控制台应用程序时,PowerShell 会返回它的 exit code(也叫做 Error Level),并存储在 $LASTEXITCODE 变量中。然而,如何获取通过 Start-Process 启动的控制台应用程序的 exit code 呢?

以下是方法:

1
2
3
4
5
6
7
8
$hostname = 'powershellmagazine.com'
# run the console-based application synchronously in the PowerShell window,
# and return the process object (-PassThru)
$process = Start-Process -FilePath ping -ArgumentList "$hostname -n 2 -w 2000" -Wait -NoNewWindow -PassThru

# the Error Level information is then found in ExitCode:
$IsOnline = $process.ExitCode -eq 0
$IsOnline

PowerShell 技能连载 - 评估 Exit Code(也叫做 Error Level – 第一部分)

当运行一个控制台应用程序时,它通常会返回一个数字型的 exit code。该 exit code 的含义取决于控制台应用程序,要查询应用程序才能理解 exit code 的含义。PowerShell 也会将 exit code 传递给用户。它通过 $LASTEXITCODE 体现。

以下是一个使用 ping.exe 来测试网络响应的例子:

1
2
3
4
5
6
7
8
9
$hostname = 'powershellmagazine.com'
# run console-based executable directly
# and disregard text results
$null = ping.exe $hostname -n 2 -w 2000
# instead look at the exit code delivered in
# $LASTEXITCODE. Ping.exe returns 0 if a
# response was received:
$IsOnline = $LASTEXITCODE -eq 0
$IsOnline

PowerShell 技能连载 - 弹出 CD 驱动器

以下是一个用 WMI 弹出 CD 驱动器的小函数。它首先向 WMI 请求所有的 CD 驱动器,然后使用 explorer 对象模型导航到该驱动器并调用它的 “Eject” 上下文菜单项。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function Eject-CD
{
$drives = Get-WmiObject Win32_Volume -Filter "DriveType=5"
if ($drives -eq $null)
{
Write-Warning "Your computer has no CD drives to eject."
return
}
$drives | ForEach-Object {
(New-Object -ComObject Shell.Application).Namespace(17).ParseName($_.Name).InvokeVerb("Eject")
}
}

Eject-CD