如何优雅地将字节类型的ResultPropertyValueCollection转换为字符串
OpenLDAP查询SSH密钥的优雅解码方案及相关疑问
问题场景
在OpenLDAP实例上查询SSH密钥时,返回的sshPublicKey值被System.DirectoryServices.ResultPropertyValueCollection包裹,内部为字节数组,直接解码会触发类型转换错误。
查询代码:
$domain = 'LDAP://ldap.local:636/dc=local' $auth = [System.DirectoryServices.AuthenticationTypes]::Anonymous $root = new-object -Typename System.DirectoryServices.DirectoryEntry($domain,$null,$null,$auth) $query = new-object System.DirectoryServices.DirectorySearcher($root, "uid=$uid", @("uid","sshPublicKey")) $results = $query.findall()
直接解码时的错误信息:
$enc = [system.text.encoding]::UTF8 $enc.GetString($results.properties.sshpublickey) Cannot convert argument "bytes", with value: "System.DirectoryServices.ResultPropertyValueCollection", for "GetString" to type "System.Byte[]": "Cannot convert value "System.DirectoryServices.ResultPropertyValueCollection" to type "System.Byte[]". Error: "Cannot convert the "System.Byte[]" value of type "System.Byte[]" to type "System.Byte"." At line:1 char:1 + $enc.GetString($results.properties.sshpublickey) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodException + FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument
目前仅能通过逐个遍历字节数组解码:
foreach ($byte in $results.properties.sshpublickey) {$enc.getstring($byte)}
优雅解码方案
利用PowerShell管道特性简化代码,无需显式foreach循环:
$sshKeys = $results.Properties.sshPublicKey | ForEach-Object { [System.Text.Encoding]::UTF8.GetString($_) }
若每个用户仅对应一个SSH密钥,可直接取集合第一个元素解码:
$sshKey = [System.Text.Encoding]::UTF8.GetString($results.Properties.sshPublicKey[0])
为什么返回字节数组而非文本
OpenLDAP中sshPublicKey属性的语法定义为octetString(字节串),而非文本类型(如directoryString)。System.DirectoryServices会严格遵循LDAP属性的语法类型返回数据,因此以字节数组形式呈现,而非直接返回文本。
能否通过配置直接获取文本
不建议修改OpenLDAP配置强制返回文本:
sshPublicKey的标准定义就是字节串,修改属性语法会破坏与其他SSH工具、客户端的兼容性,导致密钥无法正常识别。- 不存在查询级别的设置能改变属性返回类型,客户端侧完成字节到文本的转换是符合LDAP协议规范的处理方式。
内容的提问来源于stack exchange,提问作者HidalgodeArizona
相关产品推荐
相关产品推荐

