PowerShell 技能连载 - 查找 Active Directory 用户账号

有很多用于 Active Directory 的 Module 和 Cmdlet,但是有些时候用 .NET 代码来做反而更方便快捷。

比如说,如果您只是想知道,某个用户是否存在于您的 Active Directory中,那么实现查找一个用户是很容易的:

# sending LDAP query to Active Directory
$searcher = [ADSISearcher]'(&(objectClass=User)(objectCategory=person)(SamAccountName=tobias*))'
# finding first match
$searcher.FindOne()
# finding ALL matches
$searcher.FindAll()

这段代码将查找所有 SamAccountName 以 “tobias” 开头的用户账号。您可以接着用这个方法来便捷地找出这个用户所在的位置:

# find account location
$searcher.FindAll() | Select-Object -ExpandProperty Path

PowerShell 技能连载 - 在 ISE 中重设 PowerShell 宿主

想象一下您在 ISE 编辑器中长时间地编写一个脚本。当您开发的时候,您也许定义了变量、创建了函数、加载了对象,等等。

要确保您的脚本能像所希望的那样运行,您最终需要一个干净的测试环境。

获得一个干净的 PowerShell 并且移除所有变量和函数的最简单办法如下:

在 ISE 编辑器中,选择 文件 > 新建 PowerShell 选项卡。这实际上将创建一个新的 PowerShell 选项卡,以及一个全新的 PowerShell 宿主。这将确保没有任何不希望存在的旧变量和函数存在。

PowerShell 技能连载 - 查找 Cmdlet

Get-Command 可以用来查找 Cmdlet,但是在 PowerShell 3.0 中,它往往会返回比想象中还要多的 Cmdlet。由于自动加载模块的原因,Get-Command 不仅返回当前已加载 Module 中的 Cmdlet,还会返回所有可用 Module 中的 Cmdlet。

如果您仅希望在当前已加载的 Module 中查找一个 Cmdlet,请使用新的 -ListImported 参数:

PS> Get-Command -Verb Get | Measure-Object
Count    : 422

PS> Get-Command -Verb Get -ListImported | Measure-Object
Count    : 174

PowerShell 技能连载 - 从ISE编辑器中粘贴 PowerShell 代码

PowerShell ISE 编辑器的代码复制粘贴功能十分强大,例如将代码复制粘贴到 Microsoft Word 和其它文字处理器。由于 ISE 将剪贴板文字格式化为 RTF 格式,颜色代码将不会丢失。

然而,粘贴的时候字体往往太大或太小。

您可以在 ISE 编辑器中更改它。打开工具 > 选项,然后选择一个不同的字号。您在这儿选择的字号将用于粘贴的代码中。

当您更改完字号并关闭对话框之后,试着用 ISE 编辑器窗口右下角的滑块调整字体显示大小。这里的缩放级别只会影响 ISE 编辑器中的代码,并且不会影响粘贴的代码。

您也可以用鼠标滚轮来调整 ISE 编辑器中的显示字体大小。

PowerShell 技能连载 - 创建日历(和日期列表)

以下是一段创建 DateTime 集合的脚本片段。只需要指定年和月,脚本将会针对该月的每一天创建一个 DateTime 对象:

$month = 8
$year = 2013

1..[DateTime]::DaysInMonth($year,$month) |
  ForEach-Object { Get-Date -Day $_ -Month $month -Year $year }

这段代码十分有用:只要加一个日期过滤器,您就可以过滤出工作日来。它将列出指定月份的所有周一至周五(因为它排除了 weekday 0(星期日)和 weekday 6(星期六)):

$month = 8
$year = 2013

1..[DateTime]::DaysInMonth($year,$month) |
  ForEach-Object { Get-Date -Day $_ -Month $month -Year $year } |
  Where-Object { 0,6 -notcontains $_.DayOfWeek }

类似地,以下代码将统计指定月份所有星期三和星期五的天数:

$month = 8
$year = 2013

$days = 1..[DateTime]::DaysInMonth($year,$month) |
  ForEach-Object { Get-Date -Day $_ -Month $month -Year $year } |
  Where-Object { 3,5 -contains $_.DayOfWeek }

$days
"There are {0} Wednesdays and Fridays" -f $days.Count

PowerShell 技能连载 - 发生了什么?

经常地,您需要用 PowerShell 来获取数据,并且您需要提取信息的一部分并且把它们用于报表。类似如下:

$serial = Get-WmiObject -Class Win32_OperatingSystem |
  Select-Object -Property SerialNumber

"Serial Number is $serial"

但是上述代码产生的结果如下:

Serial Number is @{SerialNumber=00261-30000-00000-AA825}

当您查看 $serial 的值,它看起来似乎很正常:

PS> $serial

SerialNumber
------------
00261-30000-00000-AA825

但问题出在列头(译者注:我们只需要 SerialNumber 的值,而不是需要一个包含 SerialNumber 属性的临时对象)。您可以用 Select-Object 只选出一列,用 -ExpandProperty 而不是 -Property 就可以消除列头:

$serial = Get-WmiObject -Class Win32_OperatingSystem |
  Select-Object -ExpandProperty SerialNumber

"Serial Number is $serial"

现在,一切正常了:

Serial Number is 00261-30000-00000-AA825

PowerShell 技能连载 - 密码混淆器脚本

曾经需要将密码保存在脚本中?曾经需要自动弹出一个身份验证对话框?对于前者,将密码和其它身份信息存储在脚本中是很糟糕的对于后者,如果您这么做了的话,至少能使黑客更难于窃取信息。

以下是一个脚本生成器。运行它,并且输入一个域/用户名和密码,脚本生成器会为您生成一段新脚本。

$pwd = Read-Host 'Enter Password'
$user = Read-Host 'Enter Username'
$key = 1..32 |
  ForEach-Object { Get-Random -Maximum 256 }

$pwdencrypted = $pwd |
  ConvertTo-SecureString -AsPlainText -Force |
  ConvertFrom-SecureString -Key $key

$text = @()
$text += '$password = "{0}"' -f ($pwdencrypted -join ' ')
$text += '$key = "{0}"' -f ($key -join ' ')
$text += '$passwordSecure = ConvertTo-SecureString -String $password -Key ([Byte[]]$key.Split(" "))'
$text += '$cred = New-Object system.Management.Automation.PSCredential("{0}", $passwordSecure)' -f $user
$text += '$cred'

$newFile = $psise.CurrentPowerShellTab.Files.Add()
$newFile.Editor.Text = $text | Out-String

这段脚本包含混淆过的密码脚本,看起来大概类似这样:

$password = "76492d1116743f0423413b16050a5345MgB8AFcAMABGAEIANAB1AGEAdQA3ADUASABhAE0AMgBNADUAUwBnAFYAYQA1AEEAPQA9AHwAMgAyAGIAZgA1ADUAZgA0ADIANAA0ADUANwA2ADAAMgA5ADkAZAAxAGUANwA4ADUAZQA4ADkAZAA1AGMAMAA2AA=="
$key = "246 185 95 207 87 105 146 74 99 163 58 194 93 229 80 241 160 35 68 220 130 193 84 113 122 155 208 49 152 86 85 178"
$passwordSecure = ConvertTo-SecureString -String $password -Key ([Byte[]]$key.Split(" "))
$cred = New-Object system.Management.Automation.PSCredential("test\tobias", $passwordSecure)
$cred

当您运行它,它将生成一个 Credential 对象,您可以立即将它用于身份验证。只要将它传给一个需要 Credential 对象的形参即可。

再强调一下,这并不是安全的。但是要想获取密码的明文还需要更多点知识才行。

PowerShell 技能连载 - 检查磁盘分区和数据块大小

WMI 是一个装满信息的宝库。以下这行代码将读取本地分区以及它们的数据块大小信息:

Get-WmiObject -Class Win32_Diskpartition  |
  Select-Object -Property __Server, Caption, BlockSize

使用 Get-WmiObject-ComputerName 参数可以对一台或多台机器远程执行同样的操作。

要查看其它所有的 WMI 类,您可以替换掉 Win32_DiskPartition,试试以下的代码:

Get-WmiObject -Class Win32_* -List |
  Where-Object { ($_.Qualifiers | Select-Object -ExpandProperty Name) -notcontains 'Association' } |
  Where-Object { $_.Name -notlike '*_Perf*' }

PowerShell 技能连载 - 将Excel导出的CSV转换为UTF-8编码

当您导出 Microsoft Excel 数据表到 CSV 文件时,Excel缺省将保存为 ANSI 编码的 CSV 文件。这是很糟糕的,因为当您用 Import-Csv 导入数据到 PowerShell 中时,特殊字符将会截断(译者注:例如中文出现乱码)。

要确保特殊字符不会丢失,您必须确保导入数据之前 CSV 文件采用的是 UTF-8 编码:

$Path = 'c:\temp\somedata.csv'
(Get-Content -Path $Path) | Set-Content -Path $Path -Encoding UTF8

PowerShell 技能连载 - 查找所有用户脚本

有些时候我们会疑惑当 PowerShell 启动的时候,将执行哪些启动脚本。它们数量很多,而且各不相同,要看您运行的是 PowerShell 控制台,ISE,还是其他宿主。

然而,了解您的用户脚本是十分重要的。它们决定了应用到 PowerShell 环境的配置。

这个 Get-PSProfileStatus 函数列出了所有宿主(PowerShell 环境)可能用到的的启动脚本。它也显示了哪些脚本是物理存在的。

function Get-PSProfileStatus
{
    $profile |
      Get-Member -MemberType NoteProperty |
      Select-Object -ExpandProperty Name |
      ForEach-Object {
        $_, (Split-Path $profile.$_ -Leaf), (Split-Path $profile.$_),
                              (Test-Path -Path $profile.$_) -join ',' |
          ConvertFrom-Csv -Header Profile, FileName, FolderName, Present
        }
}

Get-PSProfileStatus

结果看起来类似这样:

将结果用管道输出到 Out-GridView 来查看,避免截断字符被截断:

Get-PSProfileStatus | Out-GridView