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

LDAP 查询条件越明确,查询速度就越快,占用的资源就越少,并且查询结果越清晰。

例如,许多人使用 objectClass 来限制查询结果为某个指定的对象类型。若只需要查询用户账户,他们常常使用 "objectClass=user" 的写法。许多人不知道计算机账户也共享这个对象类型。让我们来验证这一点:

这个例子将会查找所有 SamAccountName 以 “a” 开头,并且 objectClass=”user” 的账户。

# get all users with a SamAccountName that starts with "a"
$searcher = [ADSISearcher]"(&(objectClass=User)(sAMAccountName=a*))"

# see how long this takes
$result = Measure-Command {
  $all = $searcher.FindAll() 
  $found = $all.Count
}

$seconds = $result.TotalSeconds

"The search returned $found objects and took $sec seconds."

然后使用这行来代替上面的代码:

$searcher = [ADSISearcher]"(&(sAMAccountType=$(0x30000000))(sAMAccountName=a*))" 

当您换成这行代码以后,查询速度显著提升了。并且结果更清晰。这是因为普通用户账户和计算机账户的 SamAccountType 不同:

  • SAM_NORMAL_USER_ACCOUNT 0x30000000
  • SAM_MACHINE_ACCOUNT 0x30000001

两者的 objectClass 都属于 “User”。

查看更多

评论

PowerShell 技能连载 - 通过 SID 查找 Active Directory 账户

如果您已知账户的 SID 并且希望找到相应的 Active Directory 账户,那么 LDAP 查询并不适合这项工作。为了使它能工作,您需要将 SID 的格式改成符合 LDAP 规则的格式,这不是一个简单的过程。

以下是一个更简单的使用 LDAP 路径的办法。假设您使用 $SID 变量保存了一个 SID 字符串,并且您希望查找出和它关联的 Active Directory 账户。试试以下的代码:

$SID = '<enter SID here>'   # like S-1-5-21-1234567-...
$account = [ADSI]"LDAP://<SID=$SID>"
$account
$account.distinguishedName

查看更多

评论

用 PowerShell 处理纯文本 - 2

应朋友要求,帮忙解决一例 PowerShell 问题:

有一个 CSV 文件,其中有一个 Photo 字段存的是 BASE64 编码的字符串,这个字符串包含换行符。在 Import-Csv 的时候,Photo 字段不会作为一个整体值,而是会变成每行一个。文件的内容是这样的:

StaffNum,LogonName,ObjName,Title,Office,Department,Photo
03138,wangjunhao,王俊豪,流程优化主管,宜山路,运营平台中心/项目部,/9j/4AAQSkZJRgABAgAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0a
HBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIy
...
PyoooGSr0qRCdtFFMBy9qkFFFJCYo60w85oopgNzjoBTto9KKKQj/9k=

为了解决这个 case,先归纳它的规律:

  1. BASE64 字符串的字符集为 0..9、a..z、A..Z,以及/和=。
  2. BASE64 字符串每一行不超过 76 个字符。
  3. 如果某一行从第一个字符到最后一个字符,都符合上述 2 条规律,说明前一行并没有结束。应当把当前行拼接到前一行中。

根据以上规律编写 PowerShell 代码:

$fileName = 'AllUsers.csv'

$currentLine = ''
gc $fileName | % -process {
        if ($_ -cmatch '^[a-zA-Z0-9/+=]{1,76}$') {
            # 如果符合 BASE64 特征,说明上一行未结束。
            $currentLine += $_
        } else {
            # 如果不符合 BASE64 特征,说明上一行是完整的。
            Write-Output $currentLine
            $currentLine = $_
        }
    } -end {
        $currentLine
    } | 
ConvertFrom-Csv

完整的 .CSV 及 .PS1 文件请在这里下载

评论

快速运行 .ps1 脚本的 N 种方法

由于安全的原因,微软禁止以双击的方式执行 PowerShell 的 .ps1 脚本。但如果我们一味地追求效率,而暂时“无视”其安全性的话,要怎样快速地执行 .ps1 脚本呢?以下是 QQ 群里讨论的一些方案:

为每个 .ps1 配一个 .cmd 批处理文件

这种方法适用于可能需要将 PowerShell 脚本发送给朋友执行,而朋友可能只是初学者或普通用户的场景,并且该脚本不会修改注册表。具体做法是:将以下代码保存为一个 .cmd 文件,放在 .ps1 的同一个目录下。注意主文件名必须和 .ps1 的主文件名一致

@set Path=%Path%;%SystemRoot%\system32\WindowsPowerShell\v1.0\ & powershell -ExecutionPolicy Unrestricted -NoExit -NoProfile %~dpn0.ps1

例如,您希望朋友执行 My-Script.ps1,那么您只需要将以上代码保存为 My-Script.cmd,放在同一个目录之下发给您的朋友即可。

这种方法还有个小小的好处是,不需要为不同的 .ps1 而修改 .cmd 的内容。

用批处理文件做一个简单的菜单,列出 .ps1 文件

查看更多

评论

PowerShell 技能连载 - 在不同的 Domain 中查找

当你那使用 ADSISearcher 类型加速器来查找 Active Directory 账户时,它缺省情况下在您当前登录的域中查找。如果您需要在一个不同的域中查找,请确保相应地定义了搜索的根路径。

This example will find all accounts with a SamAccountName that starts with “tobias”, and it searches the domain “powershell.local” (adjust to a real domain name, of course):
这个例子将查找所有 SamAccountName 以 “tobias” 开头的账户,并且它在 “powershell.local” 域中搜索(当然,请根据实际情况调整名字):

# get all users with a SamAccountName that starts with "tobias"
$searcher = [ADSISearcher]"(&(objectClass=User)(objectCategory=person)(sAMAccountName=tobias*))"

# use powershell.local for searching
$domain = New-Object System.DirectoryServices.DirectoryEntry('DC=powershell,DC=local')
$searcher.SearchRoot = $domain

# execute the query
$searcher.FindAll() 

查看更多

评论

PowerShell 技能连载 - 从 DN 中获得 Domain

“DN” 指的是是 Active Directory 对象的路径,看起来大概如下:

'CN=Tobias,OU=Authors,DC=powershell,DC=local'

要获取 DN 中的域部分,请使用如下代码:

$DN = 'CN=Tobias,OU=Authors,DC=powershell,DC=local'
$pattern = '(?i)DC=\w{1,}?\b'

([RegEx]::Matches($DN, $pattern) | ForEach-Object { $_.Value }) -join ',' 

这段代码用一个正则表达式来查找 DN 的所有 DC= 部分;然后将它们用逗号分隔符连接起来。

执行结果如下:

DC=powershell,DC=local

查看更多

评论

PowerShell 技能连载 - 将二进制 SID 转换为 SID 字符串

Active Directory 账户有一个二进制形式存储的 SID。要将字节数组转换为字符串的表达形式,可以用如下的 .NET 函数:

# get current user
$searcher = [ADSISearcher]"(&(objectClass=User)(objectCategory=person)(sAMAccountName=$env:username))"
$user = $searcher.FindOne().GetDirectoryEntry() 

# get binary SID from AD account
$binarySID = $user.ObjectSid.Value

# convert to string SID
$stringSID = (New-Object System.Security.Principal.SecurityIdentifier($binarySID,0)).Value

$binarySID
$stringSID 

在这个例子中,一个 ADSI 搜索器获取当前的用户账户(返回当前登录到一个域中的用户)。然后,将二进制的 SID 转换为 SID 字符串。

查看更多

评论

下载 Visual Studio 2013

下载信息

英文版

Visual Studio Ultimate 2013 (x86) - DVD (English)
语言:英语(美国)
文件名:en_visual_studio_ultimate_2013_x86_dvd_3009107.iso
发布日期(UTC):2013-10-17 18:43:01文件大小:2.82 GB
SHA1:79DBBA7B6EF12B1A4E715A7F20951EE66FBCDAB4

中文版

Visual Studio Ultimate 2013 (x86) - DVD (Chinese-Simplified)
语言:中文(简体)
文件名:cn_visual_studio_ultimate_2013_x86_dvd_3009109.iso
发布日期(UTC):2013-10-17 18:43:01文件大小:2.87 GB
SHA1:07313542D36ED8BEEF18520AA4F15E33E32C7F77

相关链接

评论

PowerShell 技能连载 - 查找当前的脚本文件夹

从 PowerShell 3.0 开始,有一个很简单的办法来确定一个脚本所在的文件夹:$PSScriptRoot。这个变量总是保存了指定脚本所存放的文件夹路径。

通过这种方法,可以很方便地加载额外的资源,比如说其它脚本。以下代码将读取位于同一个文件夹中,一个名为 myFunctions.ps1 的脚本文件:

"$PSScriptRoot\myFunctions.ps1"

别忘了用“dot-source”语法(在路径之前加点号)。否则只会输出该路径名(而不是执行该路径表示的脚本)。

查看更多

评论

PowerShell 技能连载 - 获取 Active Directory 账户信息

在上一段脚本中,您应该已经发现了可以多么轻易地用几行 PowerShell 代码来获取 Active Directory 账户。它的结果是一个搜索结果对象,而不是实际的账户对象。

要获取一个账户的更详细信息,请使用 GetDirectoryEntry() 将搜索结果转换为一个实际的账户对象:

# get 10 results max
$searcher.SizeLimit = 10

# find account location
$searcher.FindAll() | 
  # get account object
  ForEach-Object { $_.GetDirectoryEntry() } |
  # display all properties
  Select-Object -Property * |
  # display in a grid view window (ISE needs to be installed for this step)
  Out-GridView

查看更多

评论