394 lines
13 KiB
PowerShell
394 lines
13 KiB
PowerShell
# Copyright (c) .NET Foundation. All rights reserved.
|
||
# Licensed under the MIT License. See License.txt in the project root for license information.
|
||
|
||
##############################################################################
|
||
# Example
|
||
# $result = .\httpsys.ps1 -Command Get-SslBinding -IpAddress "0x00" -Port 46300
|
||
# .\httpsys.ps1 -Command Add-SslBinding -IpAddress "0x00" -Port 46300 –Thumbprint $result.CertificateHash
|
||
# .\httpsys.ps1 -Command Delete-SslBinding -IpAddress "0x00" -Port 46300
|
||
##############################################################################
|
||
|
||
Param (
|
||
[parameter(Mandatory=$true , Position=0)]
|
||
[ValidateSet("Add-SslBinding",
|
||
"Delete-SslBinding",
|
||
"Get-SslBinding")]
|
||
[string]
|
||
$Command,
|
||
|
||
[parameter()]
|
||
[string]
|
||
$IpAddress,
|
||
|
||
[parameter()]
|
||
[string]
|
||
$Port,
|
||
|
||
[parameter()]
|
||
[string]
|
||
$Thumbprint,
|
||
|
||
[parameter()]
|
||
[string]
|
||
$TargetSSLStore,
|
||
|
||
[parameter()]
|
||
[string]
|
||
$AppId,
|
||
|
||
[parameter()]
|
||
[System.Net.IPEndPoint]
|
||
$IpEndPoint
|
||
)
|
||
|
||
|
||
# adjust parameter variables
|
||
if (-not $IpEndPoint)
|
||
{
|
||
if ($IpAddress -and $Port)
|
||
{
|
||
$IpEndPoint = New-Object "System.Net.IPEndPoint" -ArgumentList $IpAddress,$Port
|
||
}
|
||
}
|
||
|
||
if (-not $TargetSSLStore)
|
||
{
|
||
$TargetSSLStore = "Cert:\LocalMachine\My"
|
||
}
|
||
|
||
$StoreName = ($TargetSSLStore.Split("\") | Select-Object -Last 1).Trim()
|
||
|
||
$Certificate = Get-Item "$TargetSSLStore\$Thumbprint"
|
||
|
||
if (-not $AppId)
|
||
{
|
||
# Assign a random GUID for $AppId
|
||
$AppId = [guid]::NewGuid()
|
||
}
|
||
|
||
$cs = '
|
||
namespace Microsoft.IIS.Administration.Setup {
|
||
using System;
|
||
using System.Diagnostics;
|
||
using System.Diagnostics.CodeAnalysis;
|
||
using System.Net;
|
||
using System.Runtime.InteropServices;
|
||
using System.Security.Cryptography.X509Certificates;
|
||
using System.Text;
|
||
using System.ComponentModel;
|
||
|
||
public class Http {
|
||
public const int HTTP_INITIALIZE_CONFIG = 2;
|
||
public const int HTTP_SERVICE_CONFIG_SSLCERT_INFO = 1;
|
||
|
||
[DllImport("httpapi.dll", CharSet = CharSet.Auto, PreserveSig = true)]
|
||
public static extern uint HttpDeleteServiceConfiguration(IntPtr ServiceHandle, int ConfigId, ref HTTP_SERVICE_CONFIG_SSL_SET pConfigInformation, int ConfigInformationLength, IntPtr pOverlapped);
|
||
|
||
[DllImport("httpapi.dll", CharSet = CharSet.Auto, PreserveSig = true)]
|
||
public static extern uint HttpInitialize(HTTPAPI_VERSION version, uint flags, IntPtr pReserved);
|
||
|
||
[DllImport("httpapi.dll", EntryPoint = "HttpQueryServiceConfiguration",
|
||
CharSet = CharSet.Unicode, ExactSpelling = true,
|
||
CallingConvention = CallingConvention.StdCall)]
|
||
public static extern uint HttpQueryServiceConfiguration(
|
||
IntPtr serviceHandle,
|
||
HTTP_SERVICE_CONFIG_ID configID,
|
||
ref HTTP_SERVICE_CONFIG_SSL_QUERY pInputConfigInfo,
|
||
UInt32 InputConfigInfoLength,
|
||
IntPtr pOutputConfigInfo,
|
||
UInt32 OutputConfigInfoLength,
|
||
[In, Out] ref UInt32 pReturnLength,
|
||
IntPtr pOverlapped
|
||
);
|
||
|
||
[DllImport("httpapi.dll", CharSet = CharSet.Auto, PreserveSig = true)]
|
||
public static extern uint HttpSetServiceConfiguration(IntPtr ServiceHandle, int ConfigId, ref HTTP_SERVICE_CONFIG_SSL_SET pConfigInformation, int ConfigInformationLength, IntPtr pOverlapped);
|
||
|
||
[DllImport("httpapi.dll", CharSet = CharSet.Auto, PreserveSig = true)]
|
||
public static extern uint HttpTerminate(uint flags, IntPtr pReserved);
|
||
|
||
public static HTTP_SERVICE_CONFIG_SSL_SET MarshalConfigSslSet(IntPtr ptr) {
|
||
return (HTTP_SERVICE_CONFIG_SSL_SET)Marshal.PtrToStructure(ptr, typeof(HTTP_SERVICE_CONFIG_SSL_SET));
|
||
}
|
||
}
|
||
|
||
public enum HTTP_SERVICE_CONFIG_ID {
|
||
HttpServiceConfigIPListenList,
|
||
HttpServiceConfigSSLCertInfo,
|
||
HttpServiceConfigUrlAclInfo,
|
||
HttpServiceConfigMax
|
||
}
|
||
|
||
public enum HTTP_SERVICE_CONFIG_QUERY_TYPE {
|
||
HttpServiceConfigQueryExact,
|
||
HttpServiceConfigQueryNext,
|
||
HttpServiceConfigQueryMax
|
||
}
|
||
|
||
[StructLayout(LayoutKind.Sequential)]
|
||
public struct HTTPAPI_VERSION {
|
||
public ushort HttpApiMajorVersion;
|
||
public ushort HttpApiMinorVersion;
|
||
}
|
||
|
||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||
public struct HTTP_SERVICE_CONFIG_SSL_KEY {
|
||
public IntPtr pIpPort;
|
||
}
|
||
|
||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||
public struct HTTP_SERVICE_CONFIG_SSL_QUERY {
|
||
public HTTP_SERVICE_CONFIG_QUERY_TYPE QueryDesc;
|
||
public IntPtr KeyDesc;
|
||
public Int32 dwToken;
|
||
}
|
||
|
||
[StructLayout(LayoutKind.Sequential)]
|
||
public struct HTTP_SERVICE_CONFIG_SSL_SET {
|
||
public IntPtr KeyDesc;
|
||
public uint SslHashLength;
|
||
public IntPtr pSslHash;
|
||
public Guid AppId;
|
||
[MarshalAs(UnmanagedType.LPWStr)]
|
||
public string pSslCertStoreName;
|
||
public int DefaultCertCheckMode;
|
||
public int DefaultRevocationFreshnessTime;
|
||
public int DefaultRecovationUrlRetrievalTimeout;
|
||
[MarshalAs(UnmanagedType.LPWStr)]
|
||
public string pDefaultSslCtlIdentifier;
|
||
[MarshalAs(UnmanagedType.LPWStr)]
|
||
public string pDefaultSslCtlStoreName;
|
||
public int DefaultFlags;
|
||
}
|
||
}
|
||
'
|
||
|
||
$SUCCESS = 0
|
||
function InitializeInterop() {
|
||
try {
|
||
[Microsoft.IIS.Administration.Setup.Http] | Out-Null
|
||
}
|
||
catch {
|
||
Add-Type $cs
|
||
}
|
||
}
|
||
|
||
function GetIpEndpointBytes($_ipEndpoint) {
|
||
$socketAddress = $_ipEndpoint.Serialize()
|
||
$ipBytes = [System.Array]::CreateInstance([System.Byte], $socketAddress.Size)
|
||
for ($i = 0; $i -lt $socketAddress.Size; $i++) {
|
||
$ipBytes[$i] = $socketAddress[$i]
|
||
}
|
||
return $ipBytes
|
||
}
|
||
|
||
function GetBindingInfo($sslConfig) {
|
||
$hash = [System.Array]::CreateInstance([System.Byte], [int]($sslConfig.SslHashLength))
|
||
[System.Runtime.InteropServices.Marshal]::Copy($sslConfig.pSslHash, $hash, 0, $sslConfig.SslHashLength)
|
||
|
||
$socketAddressLength = 16
|
||
$sa = [System.Array]::CreateInstance([System.Byte], $socketAddressLength)
|
||
[System.Runtime.InteropServices.Marshal]::Copy($sslConfig.KeyDesc, $sa, 0, $socketAddressLength)
|
||
$socketAddress = New-Object "System.Net.SocketAddress" -ArgumentList ([System.Net.Sockets.AddressFamily]::InterNetwork, $socketAddressLength)
|
||
for ($i = 0; $i -lt $sa.Length; $i++) {
|
||
$socketAddress[$i] = $sa[$i]
|
||
}
|
||
|
||
$ep = New-Object "System.Net.IPEndPoint" -ArgumentList ([ipaddress]::Any, 0)
|
||
$endpoint = [System.Net.IPEndPoint]$ep.Create($socketAddress)
|
||
|
||
$ret = @{}
|
||
$ret.CertificateHash = [System.BitConverter]::ToString($hash).Replace("-", "")
|
||
$ret.AppId = $sslConfig.AppId
|
||
$ret.IpEndpoint = $endpoint
|
||
return $ret
|
||
}
|
||
|
||
function InitializeHttpSys() {
|
||
$v = New-Object "Microsoft.IIS.Administration.Setup.HTTPAPI_VERSION"
|
||
$V.HttpApiMajorVersion = 1
|
||
$v.HttpApiMinorVersion = 0
|
||
|
||
$result = [Microsoft.IIS.Administration.Setup.Http]::HttpInitialize($v, [Microsoft.IIS.Administration.Setup.Http]::HTTP_INITIALIZE_CONFIG, [System.IntPtr]::Zero)
|
||
|
||
if ($result -ne $SUCCESS) {
|
||
Write-Warning "Error initializing Http API"
|
||
throw [System.ComponentModel.Win32Exception] $([System.int32]$result)
|
||
}
|
||
|
||
return $result
|
||
}
|
||
|
||
function TerminateHttpSys() {
|
||
return [Microsoft.IIS.Administration.Setup.Http]::HttpTerminate([Microsoft.IIS.Administration.Setup.Http]::HTTP_INITIALIZE_CONFIG, [System.IntPtr]::Zero)
|
||
}
|
||
|
||
function Add-SslBinding($_ipEndpoint, $_certificate, $_appId) {
|
||
if ($_ipEndpoint -eq $null) {
|
||
throw "Ip Endpoint required."
|
||
}
|
||
|
||
if ($_certificate -eq $null) {
|
||
throw "Certificate required."
|
||
}
|
||
|
||
if ($appId -eq $null) {
|
||
throw "App id required."
|
||
}
|
||
|
||
<# FYI, [System.Guid]::Parse() is not supported in lower version of powershell
|
||
if (-not($_appId -is [System.Guid])) {
|
||
$_appId = [System.Guid]::Parse($_appId)
|
||
}
|
||
#>
|
||
|
||
setSslConfiguration $_ipEndpoint $_certificate $_appId
|
||
}
|
||
|
||
function Delete-SslBinding($_ipEndpoint) {
|
||
|
||
if ($_ipEndpoint -eq $null) {
|
||
throw "Ip Endpoint required."
|
||
}
|
||
|
||
setSslConfiguration $_ipEndpoint $null $([System.Guid]::Empty)
|
||
}
|
||
|
||
function Get-SslBinding($_ipEndpoint) {
|
||
|
||
if ($_ipEndpoint -eq $null) {
|
||
throw "Ip Endpoint required."
|
||
}
|
||
|
||
$bufferSize = 4096
|
||
try {
|
||
InitializeHttpSys| Out-Null
|
||
|
||
$ipBytes = [System.Byte[]]$(GetIpEndpointBytes($_ipEndpoint))
|
||
$hIp = [System.Runtime.InteropServices.GCHandle]::Alloc($ipBytes, [System.Runtime.InteropServices.GCHandleType]::Pinned)
|
||
$pIp = $hIp.AddrOfPinnedObject()
|
||
|
||
$queryParam = New-Object "Microsoft.IIS.Administration.Setup.HTTP_SERVICE_CONFIG_SSL_QUERY"
|
||
$queryParam.QueryDesc = [Microsoft.IIS.Administration.Setup.HTTP_SERVICE_CONFIG_QUERY_TYPE]::HttpServiceConfigQueryExact
|
||
$queryParam.dwToken = 0
|
||
$queryParam.KeyDesc = $pIp
|
||
|
||
$returnLen = 0
|
||
$pReturnSet = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($bufferSize)
|
||
|
||
$result = [Microsoft.IIS.Administration.Setup.Http]::HttpQueryServiceConfiguration(
|
||
[System.IntPtr]::Zero,
|
||
[Microsoft.IIS.Administration.Setup.HTTP_SERVICE_CONFIG_ID]::HttpServiceConfigSSLCertInfo,
|
||
[ref] $queryParam,
|
||
[uint32]([System.Runtime.InteropServices.Marshal]::SizeOf($queryParam)),
|
||
$pReturnSet,
|
||
$bufferSize,
|
||
[ref] $returnLen,
|
||
[System.IntPtr]::Zero)
|
||
|
||
if ($result -eq 2) {
|
||
# File not found
|
||
return $null
|
||
}
|
||
if ($result -ne $SUCCESS) {
|
||
Write-Warning "Error reading Ssl Cert Configuration"
|
||
throw [System.ComponentModel.Win32Exception] $([System.int32]$result)
|
||
}
|
||
$sslConfig = [Microsoft.IIS.Administration.Setup.Http]::MarshalConfigSslSet($pReturnSet)
|
||
return GetBindingInfo $sslConfig
|
||
}
|
||
finally {
|
||
if ($hIp -ne $null) {
|
||
$hIp.Free()
|
||
$hIp = $null
|
||
}
|
||
if ($pReturnSet -ne [System.IntPtr]::Zero) {
|
||
[System.Runtime.InteropServices.Marshal]::FreeHGlobal($pReturnSet)
|
||
$pReturnSet = [System.IntPtr]::Zero
|
||
}
|
||
TerminateHttpSys | Out-Null
|
||
}
|
||
}
|
||
|
||
function setSslConfiguration($_ipEndpoint, $_certificate, $_appId) {
|
||
|
||
try {
|
||
InitializeHttpSys| Out-Null
|
||
|
||
$sslSet = New-Object "Microsoft.IIS.Administration.Setup.HTTP_SERVICE_CONFIG_SSL_SET"
|
||
$sslSetSize = [System.Runtime.InteropServices.Marshal]::SizeOf($sslSet)
|
||
|
||
$ipBytes = [System.Byte[]]$(GetIpEndpointBytes($_ipEndpoint))
|
||
$hIp = [System.Runtime.InteropServices.GCHandle]::Alloc($ipBytes, [System.Runtime.InteropServices.GCHandleType]::Pinned)
|
||
$pIp = $hIp.AddrOfPinnedObject()
|
||
|
||
$sslSet.KeyDesc = $pIp # IntPtr
|
||
$sslSet.SslHashLength = 0
|
||
$sslSet.pSslHash = [System.IntPtr]::Zero
|
||
$sslSet.pSslCertStoreName = [System.IntPtr]::Zero
|
||
$sslSet.AppId = $_appId
|
||
|
||
if ($_certificate -ne $null) {
|
||
# Create binding
|
||
|
||
$certBytes = $_certificate.GetCertHash()
|
||
$hCertBytes = [System.Runtime.InteropServices.GCHandle]::Alloc($certBytes, [System.Runtime.InteropServices.GCHandleType]::Pinned)
|
||
$pCertBytes = $hCertBytes.AddrOfPinnedObject()
|
||
|
||
$sslSet.SslHashLength = 20
|
||
$sslSet.pSslHash = $pCertBytes
|
||
$sslSet.pSslCertStoreName = $StoreName
|
||
|
||
$result = [Microsoft.IIS.Administration.Setup.Http]::HttpSetServiceConfiguration([System.IntPtr]::Zero,
|
||
[Microsoft.IIS.Administration.Setup.Http]::HTTP_SERVICE_CONFIG_SSLCERT_INFO,
|
||
[ref]$sslSet,
|
||
$sslSetSize,
|
||
[System.IntPtr]::Zero)
|
||
}
|
||
else {
|
||
#Delete binding
|
||
$result = [Microsoft.IIS.Administration.Setup.Http]::HttpDeleteServiceConfiguration([System.IntPtr]::Zero,
|
||
[Microsoft.IIS.Administration.Setup.Http]::HTTP_SERVICE_CONFIG_SSLCERT_INFO,
|
||
[ref]$sslSet,
|
||
$sslSetSize,
|
||
[System.IntPtr]::Zero)
|
||
}
|
||
|
||
if ($result -ne $SUCCESS) {
|
||
Write-Warning "Error setting Ssl Cert Configuration"
|
||
throw [System.ComponentModel.Win32Exception] $([System.int32]$result)
|
||
}
|
||
}
|
||
finally {
|
||
if ($hIp -ne $null) {
|
||
$hIp.Free()
|
||
$hIp = $null
|
||
}
|
||
if ($hCertBytes -ne $null) {
|
||
$hCertBytes.Free()
|
||
$hCertBytes = $null
|
||
}
|
||
TerminateHttpSys| Out-Null
|
||
}
|
||
}
|
||
|
||
InitializeInterop
|
||
switch ($Command)
|
||
{
|
||
"Add-SslBinding"
|
||
{
|
||
return Add-SslBinding $IpEndPoint $Certificate $AppId
|
||
}
|
||
"Delete-SslBinding"
|
||
{
|
||
return Delete-SslBinding $IpEndpoint
|
||
}
|
||
"Get-SslBinding"
|
||
{
|
||
return Get-SslBinding $IpEndpoint
|
||
}
|
||
default
|
||
{
|
||
throw "Unknown command"
|
||
}
|
||
} |