2014-03-06 60 views

回答

7

您應該能夠通過使用HttpWebRequest對象上的ServicePoint屬性獲取公鑰。一旦我們向相關網站發出了http請求,這些必要的信息就會被填充。

如果請求到具有不可信證書的GetResponse的方法會拋出異常的現場製作,但是,ServicePoint仍將包含Certificate所以我們要確保我們忽略WebException如果狀態是信任失敗。

所以像下面應該工作:

function Get-PublicKey 
{ 
    [OutputType([byte[]])] 
    PARAM (
     [Uri]$Uri 
    ) 

    if (-Not ($uri.Scheme -eq "https")) 
    { 
     Write-Error "You can only get keys for https addresses" 
     return 
    } 

    $request = [System.Net.HttpWebRequest]::Create($uri) 

    try 
    { 
     #Make the request but ignore (dispose it) the response, since we only care about the service point 
     $request.GetResponse().Dispose() 
    } 
    catch [System.Net.WebException] 
    { 
     if ($_.Exception.Status -eq [System.Net.WebExceptionStatus]::TrustFailure) 
     { 
      #We ignore trust failures, since we only want the certificate, and the service point is still populated at this point 
     } 
     else 
     { 
      #Let other exceptions bubble up, or write-error the exception and return from this method 
      throw 
     } 
    } 

    #The ServicePoint object should now contain the Certificate for the site. 
    $servicePoint = $request.ServicePoint 
    $key = $servicePoint.Certificate.GetPublicKey() 
    Write-Output $key 
} 

Get-PublicKey -Uri "https://www.bing.com" 
Get-PublicKey -Uri "https://www.facebook.com" 

如果你要調用的方法很多次,有些可能具有相同的地址,你可能想通過ServicePointManager.FindServicePoint(System.Uri)方法來提高功能,因爲,如果已經向該站點發出了請求,它將返回一個緩存版本。所以你可以檢查服務點是否已經填充了信息。如果沒有,請進行網絡請求。如果有,只需使用已有的信息,爲自己節省一個http請求。

+0

令人驚歎的解釋。 謝謝你的時間:-) – RafaMarrara

1

http://poshcode.org/2521

function Get-WebsiteCertificate { 
    [CmdletBinding()] 
    param (
    [Parameter(Mandatory=$true)] [System.Uri] 
     $Uri, 
    [Parameter()] [System.IO.FileInfo] 
     $OutputFile, 
    [Parameter()] [Switch] 
     $UseSystemProxy, 
    [Parameter()] [Switch] 
     $UseDefaultCredentials, 
    [Parameter()] [Switch] 
     $TrustAllCertificates 
) 
    try { 
    $request = [System.Net.WebRequest]::Create($Uri) 
    if ($UseSystemProxy) { 
     $request.Proxy = [System.Net.WebRequest]::DefaultWebProxy 
    } 

    if ($UseSystemProxy -and $UseDefaultCredentials) { 
     $request.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials 
    } 

    if ($TrustAllCertificates) { 
     # Create a compilation environment 
     $Provider=New-Object Microsoft.CSharp.CSharpCodeProvider 
     $Compiler=$Provider.CreateCompiler() 
     $Params=New-Object System.CodeDom.Compiler.CompilerParameters 
     $Params.GenerateExecutable=$False 
     $Params.GenerateInMemory=$True 
     $Params.IncludeDebugInformation=$False 
     $Params.ReferencedAssemblies.Add("System.DLL") > $null 
     [email protected]' 
     namespace Local.ToolkitExtensions.Net.CertificatePolicy { 
      public class TrustAll : System.Net.ICertificatePolicy { 
      public TrustAll() { 
      } 
      public bool CheckValidationResult(System.Net.ServicePoint sp, 
       System.Security.Cryptography.X509Certificates.X509Certificate cert, 
       System.Net.WebRequest req, int problem) { 
       return true; 
      } 
      } 
     } 
'@ 
     $TAResults=$Provider.CompileAssemblyFromSource($Params,$TASource) 
     $TAAssembly=$TAResults.CompiledAssembly 

     ## We now create an instance of the TrustAll and attach it to the ServicePointManager 
     $TrustAll=$TAAssembly.CreateInstance("Local.ToolkitExtensions.Net.CertificatePolicy.TrustAll") 
     [System.Net.ServicePointManager]::CertificatePolicy=$TrustAll 
    } 

    $response = $request.GetResponse() 
    $servicePoint = $request.ServicePoint 
    $certificate = $servicePoint.Certificate 

    if ($OutputFile) { 
     $certBytes = $certificate.Export(
      [System.Security.Cryptography.X509Certificates.X509ContentType]::Cert 
     ) 
     [System.IO.File]::WriteAllBytes($OutputFile, $certBytes) 
     $OutputFile.Refresh() 
     return $OutputFile 
    } else { 
     return $certificate 
    } 
    } catch { 
    Write-Error "Failed to get website certificate. The error was '$_'." 
    return $null 
    } 

    <# 
    .SYNOPSIS 
     Retrieves the certificate used by a website. 

    .DESCRIPTION 
     Retrieves the certificate used by a website. Returns either an object or file. 

    .PARAMETER Uri 
     The URL of the website. This should start with https. 

    .PARAMETER OutputFile 
     Specifies what file to save the certificate as. 

    .PARAMETER UseSystemProxy 
     Whether or not to use the system proxy settings. 

    .PARAMETER UseDefaultCredentials 
     Whether or not to use the system logon credentials for the proxy. 

    .PARAMETER TrustAllCertificates 
     Ignore certificate errors for certificates that are expired, have a mismatched common name or are self signed. 

    .EXAMPLE 
     PS C:\> Get-WebsiteCertificate "https://www.gmail.com" -UseSystemProxy -UseDefaultCredentials -TrustAllCertificates -OutputFile C:\gmail.cer 

    .INPUTS 
     Does not accept pipeline input. 

    .OUTPUTS 
     System.Security.Cryptography.X509Certificates.X509Certificate, System.IO.FileInfo 
    #> 
} 

function Import-Certificate { 
<# 
    .SYNOPSIS 
     Imports certificate in specified certificate store. 

    .DESCRIPTION 
     Imports certificate in specified certificate store. 

    .PARAMETER CertFile 
     The certificate file to be imported. 

    .PARAMETER StoreNames 
     The certificate store(s) in which the certificate should be imported. 

    .PARAMETER LocalMachine 
     Using the local machine certificate store to import the certificate 

    .PARAMETER CurrentUser 
     Using the current user certificate store to import the certificate 

    .PARAMETER CertPassword 
     The password which may be used to protect the certificate file 

    .EXAMPLE 
     PS C:\> Import-Certificate C:\Temp\myCert.cer 

     Imports certificate file myCert.cer into the current users personal store 

    .EXAMPLE 
     PS C:\> Import-Certificate -CertFile C:\Temp\myCert.cer -StoreNames my 

     Imports certificate file myCert.cer into the current users personal store 

    .EXAMPLE 
     PS C:\> Import-Certificate -Cert $certificate -StoreNames my -StoreType LocalMachine 

     Imports the certificate stored in $certificate into the local machines personal store 

    .EXAMPLE 
     PS C:\> Import-Certificate -Cert $certificate -SN my -ST Machine 

     Imports the certificate stored in $certificate into the local machines personal store using alias names 

    .EXAMPLE 
     PS C:\> ls cert:\currentUser\TrustedPublisher | Import-Certificate -ST Machine -SN TrustedPublisher 

     Copies the certificates found in current users TrustedPublishers store to local machines TrustedPublisher using alias 

    .INPUTS 
     System.String|System.Security.Cryptography.X509Certificates.X509Certificate2, System.String, System.String 

    .OUTPUTS 
     NA 

    .NOTES 
     NAME:  Import-Certificate 
     AUTHOR: Patrick Sczepanksi (Original anti121) 
     VERSION: 20110502 
     #Requires -Version 2.0 
    .LINK 
     http://poshcode.org/2643 
     http://poshcode.org/1937 (Link to original script) 

#> 

    [CmdletBinding()] 
    param 
    (
     [Parameter(ValueFromPipeline=$true,Mandatory=$true, Position=0, ParameterSetName="CertFile")] 
     [System.IO.FileInfo] 
     $CertFile, 

     [Parameter(ValueFromPipeline=$true,Mandatory=$true, Position=0, ParameterSetName="Cert")] 
     [System.Security.Cryptography.X509Certificates.X509Certificate2] 
     $Cert, 

     [Parameter(Position=1)] 
     [Alias("SN")] 
     [string[]] $StoreNames = "My", 

     [Parameter(Position=2)] 
     [Alias("Type","ST")] 
     [ValidateSet("LocalMachine","Machine","CurrentUser","User")] 
     [string]$StoreType = "CurrentUser", 

     [Parameter(Position=3)] 
     [Alias("Password","PW")] 
     [string] $CertPassword 
    ) 

    begin 
    { 
     [void][System.Reflection.Assembly]::LoadWithPartialName("System.Security") 
    } 

    process 
    { 
     switch ($pscmdlet.ParameterSetName) { 
      "CertFile" { 
       try { 
        $Cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 $($CertFile.FullName),$CertPassword 
       } 
       catch { 
        Write-Error ("Error reading '$CertFile': $_ .") -ErrorAction:Continue 
       } 
      } 
      "Cert" { 

      } 
      default { 
       Write-Error "Missing parameter:`nYou need to specify either a certificate or a certificate file name." 
      } 
     } 

     switch -regex ($storeType) { 
      "Machine$" { $StoreScope = "LocalMachine" } 
      "User$" { $StoreScope = "CurrentUser" } 
     } 

     if ($Cert) { 
      $StoreNames | ForEach-Object { 
       $StoreName = $_ 
       Write-Verbose " [Import-Certificate] :: $($Cert.Subject) ($($Cert.Thumbprint))" 
       Write-Verbose " [Import-Certificate] :: Import into cert:\$StoreScope\$StoreName" 

       if (Test-Path "cert:\$StoreScope\$StoreName") { 
        try 
        { 
         $store = New-Object System.Security.Cryptography.X509Certificates.X509Store $StoreName, $StoreScope 
         $store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite) 
         $store.Add($Cert) 
         if ($CertFile) { 
          Write-Verbose " [Import-Certificate] :: Successfully added '$CertFile' to 'cert:\$StoreScope\$StoreName'." 
         } else { 
          Write-Verbose " [Import-Certificate] :: Successfully added '$($Cert.Subject) ($($Cert.Thumbprint))' to 'cert:\$StoreScope\$StoreName'." 
         } 
        } 
        catch 
        { 
         Write-Error ("Error adding '$($Cert.Subject) ($($Cert.Thumbprint))' to 'cert:\$StoreScope\$StoreName': $_ .") -ErrorAction:Continue 
        } 
        if ($store) { 
         $store.Close() 
        } 
       } 
       else { 
        Write-Warning "Certificate store '$StoreName' does not exist. Skipping..." 
       } 
      } 
     } else { 
      Write-Warning "No certificates found." 
     } 
    } 

    end { 
     Write-Host "Finished importing certificates." 
    } 
} 

我成功地使用這些功能是這樣的:

##Import self-signed certificate 
Get-WebsiteCertificate $baseUrl local.cer -trust | Out-Null 
Import-Certificate -certfile local.cer -SN Root | Out-Null 
+0

謝謝你的時間:-) – RafaMarrara

14

分享更多的知識:-)

$webRequest = [Net.WebRequest]::Create("https://www.outlook.com") 
try { $webRequest.GetResponse() } catch {} 
$cert = $webRequest.ServicePoint.Certificate 
$bytes = $cert.Export([Security.Cryptography.X509Certificates.X509ContentType]::Cert) 
set-content -value $bytes -encoding byte -path "$pwd\Outlook.Com.cer" 

我的同事邁克爾J.里昂與我分享了這件事。

+0

Nit:Powershell很高興地將字符串轉換爲枚舉成員,所以'$ cert.Export(「Cert」)'是一個有效的寫入。 – zneak