【问题标题】:Trouble with retrieving certificate information in Powershell?在 Powershell 中检索证书信息时遇到问题?
【发布时间】:2018-07-17 08:03:36
【问题描述】:

我正在尝试构建一个仪表板来检索我们所有服务器上的证书信息,但我在处理 powershell 对象时遇到了困难。我相信这是对象在循环内外传递的方式。我的代码有 3 次迭代。

首先,检索所有证书,但在每个对象上都将 FriendlyName 设为空白:

$serverCert = $null
$servers=get-adcomputer -filter { ( OperatingSystem -like '*server*') -AND ( Name -notlike '*-DT0094' ) } | sort Name
foreach ( $server in $servers ) { 
    $ServerName=$server.Name
    $ServerName="$ServerName.DOMAINSUFFIX"
    $serverCert += Invoke-Command -ComputerName $ServerName -Scriptblock { 
        return $(Get-ChildItem Cert:\LocalMachine\My)
    }
}
$serverCert | Select-Object PSComputerName, Thumbprint, FriendlyName, NotAfter, @{N="Template";E={($_.Extensions | ?{$_.oid.Friendlyname -match "Certificate Template Information"}).Format(0) -replace "(.+)?=(.+)\((.+)?", '$2'}}, @{N="IssuedBy";E={($_.IssuerName.Name -split ',*..=')[1]}}, @{N="Subject";E={($_.Subject -split ',*..=')[1]}} | Sort Thumbprint | Format-Table -Wrap

在这个迭代中,扩展是这样完成的:

PS C:\WINDOWS> $serverCert[0] | Select-Object -Property Extensions

Extensions
----------
{System.Security.Cryptography.Oid, System.Security.Cryptography.Oid}

在第二个中,我通过将 FriendlyName 作为一个名为“Description”的新属性显式传递来解决了这个问题......不幸的是,现在模板不显示:

$serverCert = $null
$servers=get-adcomputer -filter { ( OperatingSystem -like '*server*') -AND ( Name -notlike '*-DT0094' ) } | sort Name
foreach ( $server in $servers ) { 
    $ServerName=$server.Name
    $ServerName="$ServerName.DOMAINSUFFIX"
    $serverCert += Invoke-Command -ComputerName $ServerName -Scriptblock { 
        return $(Get-ChildItem Cert:\LocalMachine\My | Select-Object *, @{N="Description";E={$_.FriendlyName}})
    }
}
$serverCert | Select-Object PSComputerName, Thumbprint, Description, NotAfter, @{N="Template";E={($_.Extensions | ?{$_.oid.Friendlyname -match "Certificate Template Information"}).Format(0) -replace "(.+)?=(.+)\((.+)?", '$2'}}, @{N="IssuedBy";E={($_.IssuerName.Name -split ',*..=')[1]}}, @{N="Subject";E={($_.Subject -split ',*..=')[1]}} | Sort Thumbprint | Format-Table -Wrap

在这个迭代中,扩展是这样通过的,我无法显示模板名称:

PS C:\WINDOWS> $serverCert[0] | Select-Object -Property Extensions

Extensions
----------
{System.Security.Cryptography.X509Certificates.X509EnhancedKeyUsageExtension, System.Security.Cryptography.X509Certificates.X509KeyUsageExtension}

现在是第三个。这次我尝试将模板信息作为“描述”之类的属性向前传递。问题是,模板信息不清晰;显示的是其他信息,而不是友好名称。

$serverCert = $null
$servers=get-adcomputer -filter { ( OperatingSystem -like '*server*') -AND ( Name -notlike '*-DT0094' ) } | sort Name
foreach ( $server in $servers ) { 
    $ServerName=$server.Name
    $ServerName="$ServerName.DOMAINSUFFIX"
    $serverCert += Invoke-Command -ComputerName $ServerName -Scriptblock { 
        return $(Get-ChildItem Cert:\LocalMachine\My | Select-Object *, @{N="Description";E={$_.FriendlyName}}, @{N="Template";E={($_.Extensions | ?{$_.oid.Friendlyname -match "Certificate Template Information"}).Format(0) -replace "(.+)?=(.+)\((.+)?", '$2'}})
    }
}
$serverCert | Select-Object PSComputerName, Thumbprint, Description, NotAfter, Template, @{N="IssuedBy";E={($_.IssuerName.Name -split ',*..=')[1]}}, @{N="Subject";E={($_.Subject -split ',*..=')[1]}} | Sort Thumbprint | Format-Table -Wrap

某些证书的模板信息(我无法关联模板、操作系统版本...任何内容)如下所示:

模板=1.3.6.1.4.1.311.21.8.16245382.12313948.10571683.3565079.1665071.100.15924968.15384388,主要版本号=100,次要版本号=4

我被难住了。我仍然对 powershell 感到满意,但我对对象操作的了解还不够透彻,无法知道如何解决这个问题。任何帮助表示赞赏!

【问题讨论】:

  • 我现在没有时间解析你的代码并写出正确的答案,但是看看这个我作为 Github 要点的脚本:gist.github.com/bender-the-greatest/…。具体来说,findWinRMCert 函数,我在其中找到从名为 WinRM 的模板创建的证书。您可以ctrl+f 找到该函数名称。

标签: powershell


【解决方案1】:

我认为第一次迭代中未返回 FriendlyName 与使用 -ComputerName 参数时 PowerShell 反序列化数据的方式有关。

在您的第一次迭代中,尝试更改此行:

return $(Get-ChildItem Cert:\LocalMachine\My)

到:

return $(Get-ChildItem Cert:\LocalMachine\My | Select-Object *)

为了说明问题,运行这三个命令,您希望它们都包含相同的对象属性。请注意,FriendlyName 仅包含在前两个命令的输出中:

Invoke-Command -ScriptBlock { gci Cert:\LocalMachine\My } | Select-Object FriendlyName
Invoke-Command -ScriptBlock { gci Cert:\LocalMachine\My | Select-Object * }  -ComputerName . | Select-Object FriendlyName
Invoke-Command -ScriptBlock { gci Cert:\LocalMachine\My }  -ComputerName . | Select-Object FriendlyName

编辑:我可能会这样做:

Function Get-Cert-Info($ComputerName) {
  Invoke-Command -Computer $ComputerName -ScriptBlock {
    $certs = Get-ChildItem cert:\localmachine\my

    foreach($cert in $certs) {
      [pscustomobject]@{
        ComputerName = $env:COMPUTERNAME
        Thumbprint = $cert.Thumbprint
        Description = $cert.FriendlyName
        TemplateName = $(
          $Template = $cert.Extensions | Where-Object { $_.oid.FriendlyName -match "Certificate Template Information" }
          if($Template) { 
            ($Template.Format(0) -split "\(")[0] -replace "Template=", ""
          }
        )
        SAN=$(
          try {
            $cert.Extensions | Where-Object {$_.Oid.FriendlyName -eq "subject alternative name"} | ForEach {
              $SANString = "{0}" -f $_.Format(0)
              $SANS = $SANString -split ','

              foreach($SAN in $SANS) {
                ($SAN -split "=")[1]
              }
            }  
          } catch {
            "n/a"
          }
        )
        IssuedBy=$(($cert.IssuerName.Name -split ',')[0] -replace 'CN=', '')
        Subject=$(($cert.Subject -split ',')[0] -replace 'CN=', '')
        NotAfter=$cert.NotAfter       
      }  
    }
  }
}

$servers=get-adcomputer -filter { ( OperatingSystem -like '*server*') -AND ( Name -notlike '*-DT0094' ) } | sort Name

foreach ( $server in $servers ) { 
  Get-Cert-Info -ComputerName $server.Name
}

【讨论】:

  • 所以,你是对的,它修复了 FriendlyName...并触发了将 Extensions 对象类型翻转回第二个块中的类型!我不明白为什么指定 Extensions 属性的导出会翻转其类型。
  • 为避免序列化问题,请尝试直接在脚本块内执行所有对象属性访问和字符串操作。我不得不稍微重新格式化您的代码以将我的大脑包裹起来(对此感到抱歉),但请查看我的编辑。希望对您有所帮助。
  • 感谢您的提示。真的很有帮助
【解决方案2】:

虽然我找到了一种获取模板名称的方法,但是查找会失败,所以我在获得 ID 时做了类似于替换的操作:

# Get all certificates from all servers
clear-host
$serverCert = $null
ipconfig /flushdns
$servers=get-adcomputer -filter { OperatingSystem -like '*server*' } | sort Name
foreach ( $server in $servers ) { 
    $ServerName=$server.Name
    $ServerName="$ServerName.DOMAINSUFFIX"
    $serverCert += Invoke-Command -ComputerName $ServerName -Scriptblock { 
        return $(Get-ChildItem Cert:\LocalMachine\My | Select-Object *, @{N="Description";E={$_.FriendlyName}}, @{N="TemplateName";E={($_.Extensions | ?{$_.oid.Friendlyname -match "Certificate Template Information"}).Format(0) -replace "(.+)?=(.+)\((.+)?", '$2' -replace 'Template=', '' -replace '1.3.6.1.4.1.311.21.8.16245382.12313948.10571683.3565079.1665071.100.15924968.15384388.*', 'SCCM Client Certificate' -replace '1.3.6.1.4.1.311.21.8.16245382.12313948.10571683.3565079.1665071.100.9941395.14900143.*','IIS Web Servers' -replace '1.3.6.1.4.1.311.21.8.16245382.12313948.10571683.3565079.1665071.100.1979823.4984146.*','WSUS Web Server Certificate'}})
    }
}
$serverCert | Select-Object PSComputerName, Thumbprint, Description, NotAfter, TemplateName, @{N="IssuedBy";E={($_.IssuerName.Name -split ',*..=')[1]}}, @{N="Subject";E={($_.Subject -split ',*..=')[1]}} | Sort NotAfter, PSComputerName | Format-Table -Wrap

【讨论】:

    猜你喜欢
    • 2018-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多