233 lines
8.5 KiB
PowerShell
233 lines
8.5 KiB
PowerShell
# Copyright (c) Microsoft Corporation.
|
|
# Licensed under the MIT License.
|
|
|
|
#####################################################################################################
|
|
#
|
|
# Registers the WinRM endpoint for this instance of PowerShell.
|
|
#
|
|
# 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.
|
|
#
|
|
# Assumptions:
|
|
# 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
|
|
# per PowerShell version. However, multiple endpoints may be manually registered for a given
|
|
# plugin.
|
|
#
|
|
#####################################################################################################
|
|
[CmdletBinding(DefaultParameterSetName = "NotByPath")]
|
|
param
|
|
(
|
|
[parameter(Mandatory = $true, ParameterSetName = "ByPath")]
|
|
[switch]$Force,
|
|
[string]
|
|
$PowerShellHome
|
|
)
|
|
|
|
Set-StrictMode -Version 3.0
|
|
|
|
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
|
|
}
|
|
function Register-WinRmPlugin
|
|
{
|
|
param
|
|
(
|
|
#
|
|
# Expected Example:
|
|
# %windir%\\system32\\PowerShell\\6.0.0\\pwrshplugin.dll
|
|
#
|
|
[string]
|
|
[parameter(Mandatory=$true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
$pluginAbsolutePath,
|
|
|
|
#
|
|
# Expected Example: powershell.6.0.0-beta.3
|
|
#
|
|
[string]
|
|
[parameter(Mandatory=$true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
$pluginEndpointName
|
|
)
|
|
|
|
$regKey = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WSMAN\Plugin\$pluginEndpointName"
|
|
|
|
$pluginArchitecture = "64"
|
|
if ($env:PROCESSOR_ARCHITECTURE -match "x86" -or $env:PROCESSOR_ARCHITECTURE -eq "ARM")
|
|
{
|
|
$pluginArchitecture = "32"
|
|
}
|
|
$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>
|
|
<Param Name="PSVersion" Value="7.0"/>
|
|
</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>
|
|
"@
|
|
$valueString = $regKeyValueFormatString -f $pluginEndpointName, $pluginAbsolutePath, $pluginArchitecture
|
|
|
|
New-Item $regKey -Force > $null
|
|
New-ItemProperty -Path $regKey -Name ConfigXML -Value $valueString > $null
|
|
}
|
|
|
|
function New-PluginConfigFile
|
|
{
|
|
[CmdletBinding(SupportsShouldProcess, ConfirmImpact="Medium")]
|
|
param
|
|
(
|
|
[string]
|
|
[parameter(Mandatory=$true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
$pluginFile,
|
|
|
|
[string]
|
|
[parameter(Mandatory=$true)]
|
|
[ValidateNotNullOrEmpty()]
|
|
$targetPsHomeDir
|
|
)
|
|
|
|
# This always overwrites the file with a new version of it if the
|
|
# script is invoked multiple times.
|
|
Set-Content -Path $pluginFile -Value "PSHOMEDIR=$targetPsHomeDir" -ErrorAction Stop
|
|
Add-Content -Path $pluginFile -Value "CORECLRDIR=$targetPsHomeDir" -ErrorAction Stop
|
|
|
|
Write-Verbose "Created Plugin Config File: $pluginFile" -Verbose
|
|
}
|
|
|
|
function Install-PluginEndpoint {
|
|
[CmdletBinding(SupportsShouldProcess, ConfirmImpact="Medium")]
|
|
param (
|
|
[Parameter()] [bool] $Force,
|
|
[switch]
|
|
$VersionIndependent
|
|
)
|
|
|
|
######################
|
|
# #
|
|
# Install the plugin #
|
|
# #
|
|
######################
|
|
|
|
if (-not [String]::IsNullOrEmpty($PowerShellHome))
|
|
{
|
|
$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()
|
|
}
|
|
Write-Verbose "PowerShellHome: $targetPsHome" -Verbose
|
|
|
|
# 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)
|
|
}
|
|
}
|
|
|
|
Write-Verbose "Using PowerShell Version: $targetPsVersion" -Verbose
|
|
|
|
$pluginEndpointName = "PowerShell.$targetPsVersion"
|
|
|
|
$endPoint = Get-PSSessionConfiguration $pluginEndpointName -Force:$Force -ErrorAction silentlycontinue 2>&1
|
|
|
|
# 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
|
|
}
|
|
|
|
if (!$PSCmdlet.ShouldProcess($pluginEndpointName)) {
|
|
return
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
$resolvedPluginAbsolutePath = ""
|
|
if (! (Test-Path $pluginBasePath))
|
|
{
|
|
Write-Verbose "Creating $pluginBasePath"
|
|
$resolvedPluginAbsolutePath = New-Item -Type Directory -Path $pluginBasePath
|
|
}
|
|
else
|
|
{
|
|
$resolvedPluginAbsolutePath = Resolve-Path $pluginBasePath
|
|
}
|
|
|
|
$pluginPath = Join-Path $resolvedPluginAbsolutePath "pwrshplugin.dll"
|
|
|
|
# This is forced to ensure the the file is placed correctly
|
|
Copy-Item $targetPsHome\pwrshplugin.dll $resolvedPluginAbsolutePath -Force -Verbose -ErrorAction Stop
|
|
|
|
$pluginFile = Join-Path $resolvedPluginAbsolutePath "RemotePowerShellConfig.txt"
|
|
New-PluginConfigFile $pluginFile (Resolve-Path $targetPsHome)
|
|
|
|
# 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
|
|
{
|
|
Write-Host "`nGet-PSSessionConfiguration $pluginEndpointName" -ForegroundColor "green"
|
|
Get-PSSessionConfiguration $pluginEndpointName -ErrorAction Stop
|
|
}
|
|
catch [Microsoft.PowerShell.Commands.WriteErrorException]
|
|
{
|
|
throw "No remoting session configuration matches the name $pluginEndpointName."
|
|
}
|
|
}
|
|
|
|
Install-PluginEndpoint -Force $Force
|
|
Install-PluginEndpoint -Force $Force -VersionIndependent
|
|
|
|
Write-Host "Restarting WinRM to ensure that the plugin configuration change takes effect.`nThis is required for WinRM running on Windows SKUs prior to Windows 10." -ForegroundColor Magenta
|
|
Restart-Service winrm
|
|
|