2020-03-24 19:08:37 +01:00
# Copyright (c) Microsoft Corporation.
2018-02-13 18:23:53 +01:00
# Licensed under the MIT License.
2016-08-07 04:45:41 +02:00
#####################################################################################################
#
# Registers the WinRM endpoint for this instance of PowerShell.
#
2017-10-10 01:13:15 +02:00
# If the parameters '-PowerShellHome' were specified, it means that the script will be registering
# an instance of PowerShell from another instance of PowerShell.
#
# If no parameter is specified, it means that this instance of PowerShell is registering itself.
#
2016-08-07 04:45:41 +02:00
# Assumptions:
2017-10-10 01:13:15 +02:00
# 1. The CoreCLR and the the PowerShell assemblies are side-by-side in $PSHOME
# 2. Plugins are registered by version number. Only one plugin can be automatically registered
2016-08-07 04:45:41 +02:00
# per PowerShell version. However, multiple endpoints may be manually registered for a given
# plugin.
#
#####################################################################################################
2017-10-10 01:13:15 +02:00
[ CmdletBinding ( DefaultParameterSetName = " NotByPath " ) ]
2016-08-07 04:45:41 +02:00
param
(
2017-10-10 01:13:15 +02:00
[ parameter ( Mandatory = $true , ParameterSetName = " ByPath " ) ]
2018-04-10 21:21:44 +02:00
[ switch ] $Force ,
2016-08-08 18:31:17 +02:00
[ string ]
2017-10-10 01:13:15 +02:00
$PowerShellHome
2016-08-07 04:45:41 +02:00
)
2020-02-03 18:44:10 +01:00
Set-StrictMode -Version 3.0
2018-04-10 21:21:44 +02:00
if ( ! ( [ Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity ] :: GetCurrent ( ) ) . IsInRole ( [ Security.Principal.WindowsBuiltInRole ] " Administrator " ) )
{
Write-Error " WinRM registration requires Administrator rights. To run this cmdlet, start PowerShell with the `" Run as administrator `" option. "
return
}
2016-08-07 04:45:41 +02:00
function Register-WinRmPlugin
{
param
(
#
# Expected Example:
# %windir%\\system32\\PowerShell\\6.0.0\\pwrshplugin.dll
#
[ string ]
[ parameter ( Mandatory = $true ) ]
[ ValidateNotNullOrEmpty ( ) ]
$pluginAbsolutePath ,
#
2017-10-10 01:13:15 +02:00
# Expected Example: powershell.6.0.0-beta.3
2016-08-07 04:45:41 +02:00
#
[ string ]
[ parameter ( Mandatory = $true ) ]
[ ValidateNotNullOrEmpty ( ) ]
$pluginEndpointName
)
2017-12-09 00:43:53 +01:00
$regKey = " HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Plugin\ $pluginEndpointName "
2016-08-07 04:45:41 +02:00
2016-11-16 20:16:51 +01:00
$pluginArchitecture = " 64 "
2017-12-09 00:43:53 +01:00
if ( $env:PROCESSOR_ARCHITECTURE -match " x86 " -or $env:PROCESSOR_ARCHITECTURE -eq " ARM " )
2016-11-16 20:16:51 +01:00
{
$pluginArchitecture = " 32 "
}
2017-12-09 00:43:53 +01:00
$regKeyValueFormatString = @"
< PlugInConfiguration xmlns = " http://schemas.microsoft.com/wbem/wsman/1/config/PluginConfiguration " Name = " {0} " Filename = " {1} "
SDKVersion = " 2 " XmlRenderingType = " text " Enabled = " True " OutputBufferingMode = " Block " ProcessIdleTimeoutSec = " 0 " Architecture = " {2} "
UseSharedProcess = " false " RunAsUser = " " RunAsPassword = " " AutoRestart = " false " >
< InitializationParameters >
2019-05-21 07:43:51 +02:00
< Param Name = " PSVersion " Value = " 7.0 " / >
2017-12-09 00:43:53 +01:00
< / InitializationParameters >
< Resources >
< Resource ResourceUri = " http://schemas.microsoft.com/powershell/{0} " SupportsOptions = " true " ExactMatch = " true " >
< Security Uri = " http://schemas.microsoft.com/powershell/{0} " ExactMatch = " true "
Sddl = " O:NSG:BAD:P(A;;GA;;;BA)S:P(AU;FA;GA;;;WD)(AU;SA;GXGW;;;WD) " / >
< Capability Type = " Shell " / >
< / Resource >
< / Resources >
< Quotas IdleTimeoutms = " 7200000 " MaxConcurrentUsers = " 5 " MaxProcessesPerShell = " 15 " MaxMemoryPerShellMB = " 1024 " MaxShellsPerUser = " 25 "
MaxConcurrentCommandsPerShell = " 1000 " MaxShells = " 25 " MaxIdleTimeoutms = " 43200000 " / >
< / PlugInConfiguration >
" @
2016-11-16 20:16:51 +01:00
$valueString = $regKeyValueFormatString -f $pluginEndpointName , $pluginAbsolutePath , $pluginArchitecture
2016-08-07 04:45:41 +02:00
2017-12-09 00:43:53 +01:00
New-Item $regKey -Force > $null
New-ItemProperty -Path $regKey -Name ConfigXML -Value $valueString > $null
2016-08-07 04:45:41 +02:00
}
2018-04-10 21:21:44 +02:00
function New-PluginConfigFile
2016-08-07 04:45:41 +02:00
{
2018-04-10 21:21:44 +02:00
[ CmdletBinding ( SupportsShouldProcess , ConfirmImpact = " Medium " ) ]
2016-08-07 04:45:41 +02:00
param
(
[ string ]
[ parameter ( Mandatory = $true ) ]
[ ValidateNotNullOrEmpty ( ) ]
2016-08-08 18:31:17 +02:00
$pluginFile ,
[ string ]
[ parameter ( Mandatory = $true ) ]
[ ValidateNotNullOrEmpty ( ) ]
2016-08-12 23:35:43 +02:00
$targetPsHomeDir
2016-08-07 04:45:41 +02:00
)
# This always overwrites the file with a new version of it if the
# script is invoked multiple times.
2018-04-10 21:21:44 +02:00
Set-Content -Path $pluginFile -Value " PSHOMEDIR= $targetPsHomeDir " -ErrorAction Stop
Add-Content -Path $pluginFile -Value " CORECLRDIR= $targetPsHomeDir " -ErrorAction Stop
2016-08-07 04:45:41 +02:00
2017-12-09 00:43:53 +01:00
Write-Verbose " Created Plugin Config File: $pluginFile " -Verbose
2016-08-07 04:45:41 +02:00
}
2018-04-10 21:21:44 +02:00
function Install-PluginEndpoint {
[ CmdletBinding ( SupportsShouldProcess , ConfirmImpact = " Medium " ) ]
param (
[ Parameter ( ) ] [ bool ] $Force ,
[ switch ]
$VersionIndependent
)
2016-08-07 04:45:41 +02:00
2018-04-10 21:21:44 +02:00
######################
# #
# Install the plugin #
# #
######################
2020-02-03 18:44:10 +01:00
2019-09-16 22:16:24 +02:00
if ( -not [ String ] :: IsNullOrEmpty ( $PowerShellHome ) )
2018-04-10 21:21:44 +02:00
{
$targetPsHome = $PowerShellHome
$targetPsVersion = & " $targetPsHome \pwsh " -NoProfile -Command '$PSVersionTable.PSVersion.ToString()'
}
else
{
## Get the PSHome and PSVersion using the current powershell instance
$targetPsHome = $PSHOME
$targetPsVersion = $PSVersionTable . PSVersion . ToString ( )
}
2018-06-20 02:53:32 +02:00
Write-Verbose " PowerShellHome: $targetPsHome " -Verbose
2016-08-08 18:31:17 +02:00
2018-04-10 21:21:44 +02:00
# For default, not tied to the specific version endpoint, we apply
# only first number in the PSVersion string to the endpoint name.
# Example name: 'PowerShell.6'.
if ( $VersionIndependent ) {
$dotPos = $targetPsVersion . IndexOf ( " . " )
if ( $dotPos -ne -1 ) {
$targetPsVersion = $targetPsVersion . Substring ( 0 , $dotPos )
}
}
2017-10-10 01:13:15 +02:00
2018-04-10 21:21:44 +02:00
Write-Verbose " Using PowerShell Version: $targetPsVersion " -Verbose
2016-08-07 04:45:41 +02:00
2018-04-10 21:21:44 +02:00
$pluginEndpointName = " PowerShell. $targetPsVersion "
2016-08-07 04:45:41 +02:00
2018-04-10 21:21:44 +02:00
$endPoint = Get-PSSessionConfiguration $pluginEndpointName -Force: $Force -ErrorAction silentlycontinue 2 > & 1
2016-08-07 04:45:41 +02:00
2018-04-10 21:21:44 +02:00
# If endpoint exists and -Force parameter was not used, the endpoint would not be overwritten.
if ( $endpoint -and ! $Force )
{
Write-Error -Category ResourceExists -ErrorId " PSSessionConfigurationExists " -Message " Endpoint $pluginEndpointName already exists. "
return
}
2016-08-07 04:45:41 +02:00
2018-04-10 21:21:44 +02:00
if ( ! $PSCmdlet . ShouldProcess ( $pluginEndpointName ) ) {
return
}
2016-08-07 04:45:41 +02:00
2018-06-20 02:53:32 +02:00
if ( $PSVersionTable . PSVersion -lt " 6.0 " )
{
# This script is primarily used from Windows PowerShell for Win10 IoT and NanoServer to setup PSCore6 remoting endpoint
# so it's ok to hardcode to 'C:\Windows' for those systems
$pluginBasePath = Join-Path " C:\Windows\System32\PowerShell " $targetPsVersion
}
else
{
$pluginBasePath = Join-Path ( [ System.Environment ] :: GetFolderPath ( [ System . Environment + SpecialFolder ] :: Windows ) + " \System32\PowerShell " ) $targetPsVersion
}
2016-08-07 04:45:41 +02:00
2018-04-10 21:21:44 +02:00
$resolvedPluginAbsolutePath = " "
if ( ! ( Test-Path $pluginBasePath ) )
{
Write-Verbose " Creating $pluginBasePath "
$resolvedPluginAbsolutePath = New-Item -Type Directory -Path $pluginBasePath
}
else
{
$resolvedPluginAbsolutePath = Resolve-Path $pluginBasePath
}
2016-08-07 04:45:41 +02:00
2018-04-10 21:21:44 +02:00
$pluginPath = Join-Path $resolvedPluginAbsolutePath " pwrshplugin.dll "
2016-08-07 04:45:41 +02:00
2018-04-10 21:21:44 +02:00
# This is forced to ensure the the file is placed correctly
Copy-Item $targetPsHome \ pwrshplugin . dll $resolvedPluginAbsolutePath -Force -Verbose -ErrorAction Stop
2016-08-07 04:45:41 +02:00
2018-04-10 21:21:44 +02:00
$pluginFile = Join-Path $resolvedPluginAbsolutePath " RemotePowerShellConfig.txt "
New-PluginConfigFile $pluginFile ( Resolve-Path $targetPsHome )
2016-08-07 04:45:41 +02:00
2018-04-10 21:21:44 +02:00
# Register the plugin
Register-WinRmPlugin $pluginPath $pluginEndpointName
####################################################################
# #
# Validations to confirm that everything was registered correctly. #
# #
####################################################################
if ( ! ( Test-Path $pluginFile ) )
{
throw " WinRM Plugin configuration file not created. Expected = $pluginFile "
}
if ( ! ( Test-Path $resolvedPluginAbsolutePath \ pwrshplugin . dll ) )
{
throw " WinRM Plugin DLL missing. Expected = $resolvedPluginAbsolutePath \pwrshplugin.dll "
}
try
{
2020-05-07 14:00:30 +02:00
Write-Host " `n Get-PSSessionConfiguration $pluginEndpointName " -ForegroundColor " green "
2018-04-10 21:21:44 +02:00
Get-PSSessionConfiguration $pluginEndpointName -ErrorAction Stop
}
catch [ Microsoft.PowerShell.Commands.WriteErrorException ]
{
throw " No remoting session configuration matches the name $pluginEndpointName . "
}
2016-08-07 04:45:41 +02:00
}
2018-04-10 21:21:44 +02:00
Install-PluginEndpoint -Force $Force
Install-PluginEndpoint -Force $Force -VersionIndependent
2020-05-07 14:00:30 +02:00
Write-Host " Restarting WinRM to ensure that the plugin configuration change takes effect. `n This is required for WinRM running on Windows SKUs prior to Windows 10. " -ForegroundColor Magenta
2016-08-11 05:48:43 +02:00
Restart-Service winrm