PSModules/Carbon.Windows.HttpServer/1.0.0/Carbon.Windows.HttpServer.psm1
# Copyright WebMD Health Services # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License #Requires -Version 5.1 Set-StrictMode -Version 'Latest' # Functions should use $script:moduleRoot as the relative root from which to find # things. A published module has its function appended to this file, while a # module in development has its functions in the Functions directory. $script:moduleRoot = $PSScriptRoot Add-Type -TypeDefinition (Get-Content -Raw -Path (Join-Path -Path $script:moduleRoot -ChildPath 'src\Http.cs' -Resolve)) # Store each of your module's functions in its own file in the Functions # directory. On the build server, your module's functions will be appended to # this file, so only dot-source files that exist on the file system. This allows # developers to work on a module without having to build it first. Grab all the # functions that are in their own files. $functionsPath = Join-Path -Path $script:moduleRoot -ChildPath 'Functions\*.ps1' if( (Test-Path -Path $functionsPath) ) { foreach( $functionPath in (Get-Item $functionsPath) ) { . $functionPath.FullName } } function Get-CSslCertificateBinding { <# .SYNOPSIS Gets the SSL certificate bindings on this computer. .DESCRIPTION Windows binds SSL certificates to an IP addresses/port combination. This function gets all the SSL bindings on this computer, or a binding for a specific IP/port, or $null if one doesn't exist. The bindings are returned as `Carbon.Windows.HttpServer.SslCertificateBinding` objects. .OUTPUTS Carbon.Windows.HttpServer.SslCertificateBinding. .EXAMPLE > Get-CSslCertificateBinding Gets all the SSL certificate bindings on the local computer. .EXAMPLE > Get-CSslCertificateBinding -IPAddress 42.37.80.47 -Port 443 Gets the SSL certificate bound to 42.37.80.47, port 443. .EXAMPLE > Get-CSslCertificateBinding -Port 443 Gets the default SSL certificate bound to ALL the computer's IP addresses on port 443. #> [CmdletBinding()] [OutputType([Carbon.Windows.HttpServer.SslCertificateBinding])] param( # The IP address whose certificate(s) to get. Should be in the form IP:port. Optional. [ipaddress] $IPAddress, # The port whose certificate(s) to get. Optional. [UInt16] $Port ) Set-StrictMode -Version 'Latest' Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState [Carbon.Windows.HttpServer.SslCertificateBinding]::GetSslCertificateBindings() | Where-Object { if( $IPAddress ) { return $_.IPAddress -eq $IPAddress } return $true } | Where-Object { if( $Port ) { return $_.Port -eq $Port } return $true } } function Invoke-Netsh { <# .SYNOPSIS INTERNAL. .DESCRIPTION INTERNAL. .EXAMPLE INTERNAL. #> [CmdletBinding(SupportsShouldProcess)] param( # The target of the action. [Parameter(Mandatory)] [String] $Target, # The action/command being performed. [Parameter(Mandatory)] [String] $Action, # The command to run. [Parameter(Mandatory, ValueFromRemainingArguments, Position=0)] [String[]] $ArgumentList ) Set-StrictMode -Version 'Latest' Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState if (-not $PSCmdlet.ShouldProcess($Target, $Action)) { return } Write-Information "netsh $($ArgumentList -join ' ')" $output = netsh $ArgumentList if( $LASTEXITCODE ) { $output = $output -join [Environment]::NewLine $msg = "Netsh command ""$($Action)"" on ""$($Target)"" exited with code $($LASTEXITCODE): $($output)" Write-Error -Message $msg -ErrorAction $ErrorActionPreference return } $output | Where-Object { $null -ne $_ } | Write-Verbose } function Remove-CSslCertificateBinding { <# .SYNOPSIS Removes an SSL certificate binding. .DESCRIPTION Uses the netsh command line application to remove an SSL certificate binding for an IP/port combination. If the binding doesn't exist, nothing is changed. .EXAMPLE > Remove-CSslCertificateBinding -IPAddress '45.72.89.57' -Port 443 Removes the SSL certificate bound to IP 45.72.89.57 on port 443. .EXAMPLE > Remove-CSslCertificateBinding Removes the default SSL certificate from port 443. The default certificate is bound to all IP addresses. #> [CmdletBinding(SupportsShouldProcess)] param( # The IP address whose binding to remove. Default is all IP addresses. [ipaddress] $IPAddress = '0.0.0.0', # The port of the binding to remove. Default is port 443. [UInt16] $Port = 443 ) Set-StrictMode -Version 'Latest' Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState if (-not (Test-CSslCertificateBinding -IPAddress $IPAddress -Port $Port)) { return } if( $IPAddress.AddressFamily -eq [Net.Sockets.AddressFamily]::InterNetworkV6 ) { $ipPort = '[{0}]:{1}' -f $IPAddress,$Port } else { $ipPort = '{0}:{1}' -f $IPAddress,$Port } Invoke-Netsh http delete sslcert ipPort=$ipPort ` -Target $ipPort ` -Action "removing SSL certificate binding" } function Set-CSslCertificateBinding { <# .SYNOPSIS Sets an SSL certificate binding for a given IP/port. .DESCRIPTION Uses the netsh command line application to set the certificate for an IP address and port. If a binding already exists for the IP/port, it is removed, and the new binding is created. Beginning with Carbon 2.0, returns a `Carbon.Windows.HttpServer.SslCertificateBinding` object for the binding that was set. .OUTPUTS Carbon.Windows.HttpServer.SslCertificateBinding. .EXAMPLE Set-CSslCertificateBinding -IPAddress 43.27.89.54 -Port 443 -ApplicationID 88d1f8da-aeb5-40a2-a5e5-0e6107825df7 -Thumbprint 4789073458907345907434789073458907345907 Configures the computer to use the 478907345890734590743 certificate on IP 43.27.89.54, port 443. .EXAMPLE Set-CSslCertificateBinding -ApplicationID 88d1f8da-aeb5-40a2-a5e5-0e6107825df7 -Thumbprint 4789073458907345907434789073458907345907 Configures the compute to use the 478907345890734590743 certificate as the default certificate on all IP addresses, port 443. #> [CmdletBinding(SupportsShouldProcess)] [OutputType([Carbon.Windows.HttpServer.SslCertificateBinding])] param( [ipaddress] # The IP address for the binding. Defaults to all IP addresses. $IPAddress = '0.0.0.0', [UInt16] # The port for the binding. Defaults to 443. $Port = 443, [Parameter(Mandatory)] [Guid] # A unique ID representing the application using the binding. Create your own. $ApplicationID, [Parameter(Mandatory)] [ValidatePattern("^[0-9a-f]{40}$")] [String] # The thumbprint of the certificate to use. The certificate must be installed. $Thumbprint, [switch] # Return a `Carbon.Windows.HttpServer.SslCertificateBinding` for the configured binding. $PassThru ) Set-StrictMode -Version 'Latest' Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState if( $IPAddress.AddressFamily -eq [Net.Sockets.AddressFamily]::InterNetworkV6 ) { $ipPort = '[{0}]:{1}' -f $IPAddress,$Port } else { $ipPort = '{0}:{1}' -f $IPAddress,$Port } Remove-CSslCertificateBinding -IPAddress $IPAddress -Port $Port $action = 'creating SSL certificate binding' if( $PSCmdlet.ShouldProcess( $IPPort, $action ) ) { $appID = $ApplicationID.ToString('B') Invoke-Netsh http add sslcert ipport=$ipPort certhash=$Thumbprint appid=$appID ` -Target $ipPort ` -Action $action if( $PassThru ) { Get-CSslCertificateBinding -IPAddress $IPAddress -Port $Port } } } function Test-CSslCertificateBinding { <# .SYNOPSIS Tests if an SSL certificate binding exists. .DESCRIPTION SSL certificates are bound to IP addresses and ports. This function tests if one exists on a given IP address/port. .EXAMPLE Test-CSslCertificateBinding -Port 443 Tests if there is a default SSL certificate bound to all a machine's IP addresses on port 443. .EXAMPLE Test-CSslCertificateBinding -IPAddress 10.0.1.1 -Port 443 Tests if there is an SSL certificate bound to IP address 10.0.1.1 on port 443. .EXAMPLE Test-CSslCertificateBinding Tests if there are any SSL certificates bound to any IP address/port on the machine. #> [CmdletBinding()] param( [ipaddress] # The IP address to test for an SSL certificate. $IPAddress, [Uint16] # The port to test for an SSL certificate. $Port ) Set-StrictMode -Version 'Latest' Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState $getArgs = @{ } if( $IPAddress ) { $getArgs.IPAddress = $IPAddress } if( $Port ) { $getArgs.Port = $Port } $binding = Get-CSslCertificateBinding @getArgs if( $binding ) { return $True } else { return $False } } function Use-CallerPreference { <# .SYNOPSIS Sets the PowerShell preference variables in a module's function based on the callers preferences. .DESCRIPTION Script module functions do not automatically inherit their caller's variables, including preferences set by common parameters. This means if you call a script with switches like `-Verbose` or `-WhatIf`, those that parameter don't get passed into any function that belongs to a module. When used in a module function, `Use-CallerPreference` will grab the value of these common parameters used by the function's caller: * ErrorAction * Debug * Confirm * InformationAction * Verbose * WarningAction * WhatIf This function should be used in a module's function to grab the caller's preference variables so the caller doesn't have to explicitly pass common parameters to the module function. This function is adapted from the [`Get-CallerPreference` function written by David Wyatt](https://gallery.technet.microsoft.com/scriptcenter/Inherit-Preference-82343b9d). There is currently a [bug in PowerShell](https://connect.microsoft.com/PowerShell/Feedback/Details/763621) that causes an error when `ErrorAction` is implicitly set to `Ignore`. If you use this function, you'll need to add explicit `-ErrorAction $ErrorActionPreference` to every `Write-Error` call. Please vote up this issue so it can get fixed. .LINK about_Preference_Variables .LINK about_CommonParameters .LINK https://gallery.technet.microsoft.com/scriptcenter/Inherit-Preference-82343b9d .LINK http://powershell.org/wp/2014/01/13/getting-your-script-module-functions-to-inherit-preference-variables-from-the-caller/ .EXAMPLE Use-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState Demonstrates how to set the caller's common parameter preference variables in a module function. #> [CmdletBinding()] param ( [Parameter(Mandatory)] #[Management.Automation.PSScriptCmdlet] # The module function's `$PSCmdlet` object. Requires the function be decorated with the `[CmdletBinding()]` # attribute. $Cmdlet, [Parameter(Mandatory)] # The module function's `$ExecutionContext.SessionState` object. Requires the function be decorated with the # `[CmdletBinding()]` attribute. # # Used to set variables in its callers' scope, even if that caller is in a different script module. [Management.Automation.SessionState]$SessionState ) Set-StrictMode -Version 'Latest' # List of preference variables taken from the about_Preference_Variables and their common parameter name (taken # from about_CommonParameters). $commonPreferences = @{ 'ErrorActionPreference' = 'ErrorAction'; 'DebugPreference' = 'Debug'; 'ConfirmPreference' = 'Confirm'; 'InformationPreference' = 'InformationAction'; 'VerbosePreference' = 'Verbose'; 'WarningPreference' = 'WarningAction'; 'WhatIfPreference' = 'WhatIf'; } foreach( $prefName in $commonPreferences.Keys ) { $parameterName = $commonPreferences[$prefName] # Don't do anything if the parameter was passed in. if( $Cmdlet.MyInvocation.BoundParameters.ContainsKey($parameterName) ) { continue } $variable = $Cmdlet.SessionState.PSVariable.Get($prefName) # Don't do anything if caller didn't use a common parameter. if( -not $variable ) { continue } if( $SessionState -eq $ExecutionContext.SessionState ) { Set-Variable -Scope 1 -Name $variable.Name -Value $variable.Value -Force -Confirm:$false -WhatIf:$false } else { $SessionState.PSVariable.Set($variable.Name, $variable.Value) } } } |