PowerShell 技能连载 - 弹出 CD 驱动器
以下是一个用 WMI 弹出 CD 驱动器的小函数。它首先向 WMI 请求所有的 CD 驱动器,然后使用 explorer 对象模型导航到该驱动器并调用它的 “Eject” 上下文菜单项。
1 | function Eject-CD |
以下是一个用 WMI 弹出 CD 驱动器的小函数。它首先向 WMI 请求所有的 CD 驱动器,然后使用 explorer 对象模型导航到该驱动器并调用它的 “Eject” 上下文菜单项。
1 | function Eject-CD |
当使用 Import-Csv
导入一个 CSV 文件,需要指定一个分隔符。如果用错了,显然会导入失败。您需要事先知道 CSV 文件使用的分隔符。
以下是一个简单的实践,展示了如何判断一个给定的 CSV 文件的分隔符:
1 | function Get-CsvDelimiter($Path) |
以下是一个测试:
1 | PS> Get-Date | Export-Csv -Path $env:temp\test.csv -NoTypeInformation |
当一个 CSV 文件包含重复的表头时,它无法被导入。在前一个技能中我们掩饰了如何检测一个 CSV 文件中重复的表头。以下是一个自动更正重复项的实践。
第一步,您需要一个包含重复表头的 CSV 文件。例如在德文系统中,您可以这样创建一个文件:
1 | PS C:\> driverquery /V /FO CSV | Set-Content -Path $env:temp\test.csv -Encoding UTF8 |
快速打开该文件并检查它是否确实包含重复项。
1 | PS C:\> notepad $env:temp\test.csv |
如果没有重复项,请将某些表头重命名以制造一些重复项,并保存文件。
您现在可以用 Import-Csv
导入 CSV 文件了:
1 | PS C:\> Import-Csv -Path $env:temp\test.csv -Delimiter ',' |
这是一个新的名为 Import-CsvWithoutDuplicate
的函数,可以自动处理重复的项:
1 | function Import-CsvWithDuplicate($Path, $Delimiter=',', $Encoding='UTF8') |
通过它,您可以安全地导入 CSV 文件,不会遇到重复的表头:
1 | PS C:\> Import-CsvWithDuplicate -Path $env:temp\test.csv -Delimiter ',' |
如您所见,这个函数自动将第二个 “Status” 实例重命名为 “Status1”。
CSV 文件只是文本文件,所以可以很容易地提取它的第一行并检查它的表头。如果您手头没有一个 CSV 文件,这行代码可以快速帮您创建一个:
1 | PS C:\> Get-Process | Export-Csv -Path $env:temp\test.csv -NoTypeInformation -Encoding UTF8 -UseCulture |
现在您可以分析它的表头。这个简单的方法告诉您 CSV 文件中是否有重复的标题(在这个例子中显然不存在)。这段代码假设您的 CSV 文件分隔符是逗号。如果使用一个不同的分隔符,请调整用于分割的字符:
1 | $headers = Get-Content $env:temp\test.csv | Select-Object -First 1 |
结果如预想的:
1 | You are safe! |
如果您好奇当遇到重复的标题时会如何失败,请试试这段代码:
1 | PS C:\> driverquery /V /FO CSV | Set-Content -Path $env:temp\test.csv -Encoding UTF8 |
如果您在一个的文系统中运行这段代码,结果将会类似这样:
1 | WARNUNG: There are duplicate columns in your CSV file: |
显然,在本地化时,Microsoft 将 “State” 和 “Status” 两个单词都翻译成了德文的 “Status”,造成了重复的列标题。
当您保存日期和时间到文本中时,例如导出到 CSV 时,或创建文本报告时,DateTime
对象将会按照您的区域设置转换为相应的日期和时间格式:
1 | PS> $date = Get-Date -Date '2017-02-03 19:22:11' |
这些都是和区域有关的格式,所以当其他人打开您的数据,将它转换为真实的日期时间可能会失败。这就是为什么推荐将日期时间信息保存为文本时将它转换为区域无关的 ISO 格式:
1 | PS> Get-Date -Date $date -Format 'yyyy-MM-dd HH:mm:ss' |
该 ISO 格式重视能正确地转回 DateTime
对象,无论您的机器用的是什么语言:
1 | PS> [DateTime]'2017-02-03 19:22:11' |
另外,这种设计保证它们在使用字母排序时顺序是正确的。
在前一个技能中我们解释了如何将用时钟周期数表达的日期时间转换为真实的 DateTime
格式。然而,现实中有两种不同的时钟周期格式,以下是如何转换数字型日期时间信息的概述:
1 | PS> $date = Get-Date -Date '2017-02-03 19:22:11' |
如您所见,将时钟周期转换为 DateTime
和执行 FromBinary()
静态方法的效果是一样的。但是 FromeFileTime()
做了什么?它似乎把你发送到了遥远的将来。
这个例子显示了到底发生了什么:
1 | PS> $date1 = [DateTime]::FromBinary($ticks) |
FromeFileTime()
只是增加了 1601 年(因为闰年,实际计算结果略有出入)。Windows 的某些部分(例如 Active Directory)从 1601 年 1 月 1 日开始计算日期。对于这些情况,请使用 FromeFileTime()
来获取正确的日期时间。
有时候您可能会遇到一些奇怪的日期和时间格式,它们可能用的是类似这样的 64 位 integer 数值:636264671350358729。
如果您想将这样的“时钟周期”(Windows 中最小的时间片),只需要将数字转换为 DateTime
类型:
1 | PS> [DateTime]636264671350358729 |
类似地,要将一个日期转换为时钟周期,请试试这段代码:
1 | PS> $date = Get-Date -Date '2017-02-03 19:22:11' |
比如说,您可以利用这个时钟周期来将日期和时间序列化成非特定区域的格式。
在前一个技能中我们演示了如何在任何版本的 PowerShell 中用 .NET 方法导入数字证书。新版本的 PowerShell 有一个 “PKI” module,其中包括了 Import-Certificate
cmdlet,导入证书变得更简单了。
1 | #requires -Version 2.0 -Modules PKI |
请注意 Import-Certificate
如何通过 -CertStoreLocation
指定目标存储位置。这个命令返回导入的证书。
可以在任意版本的 PowerShell 中用 .NET 方法将证书安装到计算机中。这将导入一个证书文件到个人存储中:
1 | # importing to personal store |
您可以打开证书管理器证实这一点:
1 | PS C:\> certmgr.msc |
如果您想将证书导入到一个不同的存储位置,只需要调整创建存储对象的参数即可。
您能指出这段代码的错误吗?
1 | PS C:\> function r { "This never runs" } |
如果您执行函数 “r”,它只会返回函数的源代码。
错误的原因是函数名 “r” 和内置的别名冲突:
1 | PS C:\> Get-Alias r |
所以请始终确保知道内置的别名——它们的优先级永远比函数或其它命令高。更好的做法是,按照最佳实践,始终用 Verb-Noum 的方式来命名您的函数。