Skip to content

Instantly share code, notes, and snippets.

@jborean93
Created April 1, 2022 01:35
Show Gist options
  • Save jborean93/573695261ca50fb0142fa3f4a1a24fcd to your computer and use it in GitHub Desktop.
Save jborean93/573695261ca50fb0142fa3f4a1a24fcd to your computer and use it in GitHub Desktop.
Create pwsh wrapper for netsh.exe http add|delete|show sslcert
[Flags()] enum CertCheckMode {
VerifyClientCertRevocation = 0x00000000
VerifyRevocationUsingCacheOnly = 0x00000002
DefaultRevocationFreshnessTimeIsEnabled = 0x00000004
NoUsageCheck = 0x00010000
}
[Flags()] enum SslFlags {
None = 0x00000000
UseDsMapper = 0x00000001
NegotiateClientCert = 0x00000002
NoRawFilter = 0x00000004
Reject = 0x00000008
DisableHTTP2 = 0x00000010
DisableQUIC = 0x00000020
DisableTLS13 = 0x00000040
DisableOCSAPStapling = 0x00000080
EnableTokenBinding = 0x00000100
LogExtendedEvents = 0x00000200
DisableLegacyTls = 0x00000400
EnableSessionTicket = 0x00000800
DisableTLS12 = 0x00001000
EnableClientCorrelation = 0x00002000
}
Function Add-HttpSslCert {
<#
.SYNOPSIS
Add SSL cert binding.
.DESCRIPTION
Add SSL cert binding for an IP address, hostname, or central certificate store binding.
.PARAMETER IPPort
The IP and port to add the binding for, this is in the form 'ipaddr:port'.
.PARAMETER HostPort
The hostname and port (for SNI) to add the binding for, this is in the form 'name:port'
.PARAMETER CCS
The Central Certificate Store binding port to add the binding for.
.PARAMETER ScopedCCS
A scoped Central Certificate Store binding port to add the binding for, this is in the form 'name:port'
.PARAMETER CertificateThumbprint
The certificate thumbprint to set for the binding.
This is not used if adding a CCS or ScopedCCS binding.
.PARAMETER AppId
A unique application identifier for the owning application.
.PARAMETER CertStoreName
Store name in the local machine context that contains the certificate.
If undefined then it will default to 'My' for a HostPort binding.
.PARAMETER EnableDSMapper
Turn on DS mappers.
.PARAMETER ClientCertNegotiation
Turns on negotiation of a certificate.
.PARAMETER Reject
Reject any new matching connections.
.PARAMETER DisableHttp2
Disables HTTP2.
.PARAMETER DisableQuic
Disables QUIC.
.PARAMETER DisableLegacyTls
Disable legacy TLS protocol versions.
.PARAMETER DisableTls12
Disable TLSv1.2.
.PARAMETER DisableTls13
Disable TLSv1.3.
.PARAMETER DisableOcspStapling
Disable OCSP stapling.
.PARAMETER EnableTokenBinding
Enable token binding.
.PARAMETER LogExtendedEvents
Enable additional debug event logs.
.PARAMETER EnableSessionTicket
Enable TLS session resumption.
.EXAMPLE
$cert = Get-Item WSMan:\LocalMachine\My | Where-Object Subject -eq $subj
Add-HttpSslCert -IPPort 0.0.0.0:443 -AppId ([Guid]::NewGuid()) -CertificateThumbprint $cert.Thumbprint
.NOTES
This cmdlet is a simple wrapper around 'netsh.exe http add sslcert ...'.
Some options are only available on newer versions of Windows.
#>
[CmdletBinding(DefaultParameterSetName = "IPPort", SupportsShouldProcess)]
param (
[Parameter(Position = 0, ValueFromPipelineByPropertyName, ParameterSetName = "IPPort")]
[string]
$IPPort,
[Parameter(Position = 0, ValueFromPipelineByPropertyName, ParameterSetName = "HostPort")]
[string]
$HostPort,
[Parameter(Position = 0, ValueFromPipelineByPropertyName, ParameterSetName = "CCS")]
[string]
$CCS,
[Parameter(Position = 0, ValueFromPipelineByPropertyName, ParameterSetName = "ScopedCCS")]
[string]
$ScopedCCS,
[Parameter(Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "IPPort")]
[Parameter(Mandatory, ValueFromPipelineByPropertyName, ParameterSetName = "HostPort")]
[string]
$CertificateThumbprint,
[Parameter(Mandatory, ValueFromPipelineByPropertyName)]
[guid]
$AppId,
[Parameter(ParameterSetName = "IPPort")]
[Parameter(Mandatory, ParameterSetName = "HostPort")]
[string]
$CertStoreName,
[switch]
$EnableDSMapper,
[switch]
$ClientCertNegotiation,
[switch]
$Reject,
[switch]
$DisableHttp2,
[switch]
$DisableQuic,
[switch]
$DisableLegacyTls,
[switch]
$DisableTls12,
[switch]
$DisableTls13,
[switch]
$DisableOcspStapling,
[switch]
$EnableTokenBinding,
[switch]
$LogExtendedEvents,
[switch]
$EnableSessionTicket
)
process {
$key = if ($PSCmdlet.ParameterSetName -eq "IPPort") {
"ipport=$IPPort"
}
elseif ($PSCmdlet.PagingParameters -eq "HostPort") {
"hostnameport=$HostPort"
}
elseif ($PSCmdlet.ParameterSetName -eq "CCS") {
"ccs=$CCS"
}
else {
"scopedccs=$ScopedCCS"
}
$arguments = @(
"http"
"add"
"sslcert"
$key
"appid={$AppId}"
if ($CertificateThumbprint) { "certhash=$CertificateThumbprint" }
if ($CertStoreName) { "certstorename=$CertStoreName" }
if ($EnableDSMapper) { "dsmapperusage=enabled" }
if ($ClientCertNegotiation) { "clientcertnegotiation=enabled" }
if ($Reject) { "reject=enable" }
if ($DisableHttp2) { "disablehttp2=enable" }
if ($DisableQuic) { "disablequic=enable" }
if ($DisableLegacyTls) { "disablelegacytls=enable" }
if ($DisableTls12) { "disabletls12=enable" }
if ($DisableTls13) { "disabletls13=enable" }
if ($DisableOcspStapling) { "disableocpsstapling=enable" }
if ($EnableTokenBinding) { "enabletokenbinding=enable" }
if ($LogExtendedEvents) { "logextendedevents=enable" }
if ($EnableSessionTicket) { "enablesessionticket=enable" }
)
if ($PSCmdlet.ShouldProcess($key, "netsh.exe {0}" -f ($arguments -join " "))) {
$out = netsh.exe @arguments
if ($LASTEXITCODE) {
$err = [System.Management.Automation.ErrorRecord]::new(
[Exception]::new($out),
"netsh.http.add.sslcert",
[System.Management.Automation.ErrorCategory]::InvalidOperation,
$null)
$PSCmdlet.WriteError($err)
}
}
}
}
Function Get-HttpSslCert {
<#
.SYNOPSIS
Get HTTP sslcert binding info
.DESCRIPTION
Gets HTTP ssl binding information.
.PARAMETER IPPort
The IP and port of the binding to get the info for, this is in the form 'ipaddr:port'.
.PARAMETER HostPort
The hostname and port (SNI) of the binding to get the info for, this is in the form 'name:port'.
.PARAMETER CCS
The Central Certificate Store binding defined port to get the info for.
.PARAMETER ScopedCCS
The Central Certificate Store binding name and port to get the info for, this is in the form 'name:port'
.EXAMPLE Get all sslcert bindings
Get-HttpSslCert
.EXAMPLE Get sslcert binding for specific one
Get-HttpSslCert -IPPort 0.0.0.0:443
.NOTES
This cmdlet is a simple wrapper around 'netsh.exe http show sslcert ...'.
It uses functionality in netsh recently added in Server 2022 and Windows 11.
#>
[CmdletBinding(DefaultParameterSetName = "IPPort")]
param (
[Parameter(Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName, ParameterSetName = "IPPort")]
[AllowEmptyCollection()]
[string[]]
$IPPort = @(),
[Parameter(Position = 0, ValueFromPipelineByPropertyName, ParameterSetName = "HostPort")]
[AllowEmptyCollection()]
[string[]]
$HostPort = @(),
[Parameter(Position = 0, ValueFromPipelineByPropertyName, ParameterSetName = "CCS")]
[AllowEmptyCollection()]
[string[]]
$CCS = @(),
[Parameter(Position = 0, ValueFromPipelineByPropertyName, ParameterSetName = "ScopedCCS")]
[AllowEmptyCollection()]
[string[]]
$ScopedCCS = @()
)
process {
[string[]]$values = if ($PSCmdlet.ParameterSetName -eq "IPPort") {
$IPPort | ForEach-Object { 'ipport={0}' -f $_ }
}
elseif ($PSCmdlet.ParameterSetName -eq "HostPort") {
$HostPort | ForEach-Object { 'hostnameport={0}' -f $_ }
}
elseif ($PSCmdlet.ParameterSetName -eq "CCS") {
$CCS | ForEach-Object { 'ccs={0}' -f $_ }
}
else {
$ScopedCCS | ForEach-Object { 'scopedccs={0}' -f $_ }
}
$values = if (-not $values) { , @(, @()) } else { $values }
foreach ($id in $values) {
$arguments = @(
"http"
"show"
"sslcert"
$id
"json=enable"
)
$PSCmdlet.WriteVerbose("Running netsh.exe {0}" -f ($arguments -join " "))
$rawOut = &netsh.exe @arguments
try {
$raw = $rawOut | ConvertFrom-Json
}
catch {
$err = [System.Management.Automation.ErrorRecord]::new(
[Exception]::new("netsh failure: $rawOut"),
"netsh.http.show.sslcert",
[System.Management.Automation.ErrorCategory]::InvalidArgument,
$null)
$PSCmdlet.WriteError($err)
continue
}
$raw | Select-Object -ExpandProperty SslCertificateBindings | ForEach-Object -Process {
$certHashBytes = [System.Convert]::FromBase64String($_.SslHash)
[PSCustomObject]@{
PSTypeName = 'Netsh.SslCert'
IPPort = $_.IpPort
ConfigType = $_.ConfigType
Host = $_.Host
AppId = [Guid]::new($_.GuidString)
CertificateThumbprint = [System.BitConverter]::ToString($certHashBytes).Replace("-", "")
SslCertStoreName = $_.SslCertStoreName
DefaultCertCheckMode = [CertCheckMode]$_.DefaultCertCheckMode
DefaultRevocationFreshnessTime = $_.DefaultRevocationFreshnessTime
DefaultRevocationUrlRetrievalTimeout = $_.DefaultRevocationUrlRetrievalTimeout
DefaultSslCtlIdentifier = $_.DefaultSslCtlIdentifier
DefaultSslCtlStoreName = $_.DefaultSslCtlStoreName
DefaultFlags = [SslFlags]$_.DefaultFlags
}
}
}
}
}
Function Remove-HttpSslCert {
<#
.SYNOPSIS
Remove HTTP sslcert binding
.DESCRIPTION
Removes a HTTP ssl binding configuration for the ip/host/ccs key set.
.PARAMETER IPPort
The IP and port of the binding to remove, this is in the form 'ipaddr:port'.
.PARAMETER HostPort
The hostname and port (SNI) of the binding to remove, this is in the form 'name:port'.
.PARAMETER CCS
The Central Certificate Store binding defined port to remove.
.PARAMETER ScopedCCS
The Central Certificate Store binding name and port to remove, this is in the form 'name:port'
.EXAMPLE
Remove-HttpSslCert -IPPort 0.0.0.0:443
.NOTES
This cmdlet is a simple wrapper around 'netsh.exe http delete sslcert ...'.
#>
[CmdletBinding(DefaultParameterSetName = "IPPort", SupportsShouldProcess)]
param (
[Parameter(Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName, ParameterSetName = "IPPort")]
[string[]]
$IPPort,
[Parameter(Position = 0, ValueFromPipelineByPropertyName, ParameterSetName = "HostPort")]
[string[]]
$HostPort,
[Parameter(Position = 0, ValueFromPipelineByPropertyName, ParameterSetName = "CCS")]
[string[]]
$CCS,
[Parameter(Position = 0, ValueFromPipelineByPropertyName, ParameterSetName = "ScopedCCS")]
[string[]]
$ScopedCCS
)
process {
[string[]]$values = if ($PSCmdlet.ParameterSetName -eq "IPPort") {
$IPPort | ForEach-Object { 'ipport={0}' -f $_ }
}
elseif ($PSCmdlet.ParameterSetName -eq "HostPort") {
$HostPort | ForEach-Object { 'hostnameport={0}' -f $_ }
}
elseif ($PSCmdlet.ParameterSetName -eq "CCS") {
$CCS | ForEach-Object { 'ccs={0}' -f $_ }
}
else {
$ScopedCCS | ForEach-Object { 'scopedccs={0}' -f $_ }
}
foreach ($id in $values) {
$arguments = @(
"http"
"delete"
"sslcert"
$id
)
if ($PSCmdlet.ShouldProcess($id, "netsh.exe {0}" -f ($arguments -join " "))) {
$out = &netsh.exe @arguments
if ($LASTEXITCODE) {
$err = [System.Management.Automation.ErrorRecord]::new(
[Exception]::new($out),
"netsh.http.delete.sslcert",
[System.Management.Automation.ErrorCategory]::InvalidOperation,
$null)
$PSCmdlet.WriteError($err)
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment