MegaBites-AI/Windows-powershell
0372
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System;5using System.Collections;6using System.Collections.Generic;7using System.Collections.ObjectModel;8using System.Globalization;9using System.IO;10using System.Management.Automation;11using System.Management.Automation.Internal;12using System.Management.Automation.Language;13using System.Management.Automation.Remoting;14using System.Management.Automation.Runspaces;15using System.Security;16using System.Security.AccessControl;17using System.Security.Principal;18using System.Text;19using System.Threading;20using Dbg = System.Management.Automation.Diagnostics;21using PowerShellApi = System.Management.Automation.PowerShell;22using WSManNativeApi = System.Management.Automation.Remoting.Client.WSManNativeApi;23 24namespace Microsoft.PowerShell.Commands25{26 #region Register-PSSessionConfiguration cmdlet27 /// <summary>28 /// Class implementing Register-PSSessionConfiguration.29 /// </summary>30 [Cmdlet(VerbsLifecycle.Register, RemotingConstants.PSSessionConfigurationNoun,31 DefaultParameterSetName = PSSessionConfigurationCommandBase.NameParameterSetName,32 SupportsShouldProcess = true,33 ConfirmImpact = ConfirmImpact.Medium, HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096793")]34 public sealed class RegisterPSSessionConfigurationCommand : PSSessionConfigurationCommandBase35 {36 #region Private Data37 38 // To Escape " -- ""39 private const string newPluginSbFormat = @"40function Register-PSSessionConfiguration41{{42 [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact=""Medium"")]43 param(44 [string] $filepath,45 [string] $pluginName,46 [bool] $shouldShowUI,47 [bool] $force,48 [string] $restartWSManTarget,49 [string] $restartWSManAction,50 [string] $restartWSManRequired,51 [string] $runAsUserName,52 [system.security.securestring] $runAsPassword,53 [System.Management.Automation.Runspaces.PSSessionConfigurationAccessMode] $accessMode,54 [bool] $isSddlSpecified,55 [string] $configTableSddl,56 [bool] $noRestart57 )58 59 begin60 {{61 ## Construct SID for network users62 [system.security.principal.wellknownsidtype]$evst = ""NetworkSid""63 $networkSID = new-object system.security.principal.securityidentifier $evst,$null64 65 ## If all session configurations have Network Access disabled,66 ## then we create this endpoint as Local as well.67 $newSDDL = $null68 $foundRemoteEndpoint = $false;69 Get-PSSessionConfiguration -Force:$force | Foreach-Object {{70 if ($_.Enabled)71 {{72 $sddl = $null73 if ($_.psobject.members[""SecurityDescriptorSddl""])74 {{75 $sddl = $_.psobject.members[""SecurityDescriptorSddl""].Value76 }}77 78 if($sddl)79 {{80 # See if it has 'Disable Network Access'81 $sd = new-object system.security.accesscontrol.commonsecuritydescriptor $false,$false,$sddl82 $disableNetworkExists = $false83 $sd.DiscretionaryAcl | ForEach-Object {{84 if (($_.acequalifier -eq ""accessdenied"") -and ($_.securityidentifier -match $networkSID) -and ($_.AccessMask -eq 268435456))85 {{86 $disableNetworkExists = $true87 }}88 }}89 90 if(-not $disableNetworkExists) {{ $foundRemoteEndpoint = $true }}91 }}92 }}93 }}94 95 if(-not $foundRemoteEndpoint)96 {{97 $newSDDL = ""{1}""98 }}99 }}100 101 process102 {{103 if ($force)104 {{105 if (Test-Path (Join-Path WSMan:\localhost\Plugin ""$pluginName""))106 {{107 Unregister-PSSessionConfiguration -name ""$pluginName"" -force108 }}109 }}110 111 try112 {{113 new-item -path WSMan:\localhost\Plugin -file ""$filepath"" -name ""$pluginName""114 }}115 catch [System.InvalidOperationException] # WS2012/R2 WinRM w/o WMF has limitation where MaxConcurrentUsers can't be greater than 100116 {{117 $xml = [xml](get-content ""$filepath"")118 $xml.PlugInConfiguration.Quotas.MaxConcurrentUsers = 100119 Set-Content -path ""$filepath"" -Value $xml.OuterXml120 new-item -path WSMan:\localhost\Plugin -file ""$filepath"" -name ""$pluginName""121 }}122 123 if ($? -and $runAsUserName)124 {{125 try {{126 $runAsCredential = new-object system.management.automation.PSCredential($runAsUserName, $runAsPassword)127 $pluginWsmanRunAsUserPath = [System.IO.Path]::Combine(""WSMan:\localhost\Plugin"", ""$pluginName"", ""RunAsUser"")128 set-item -WarningAction SilentlyContinue $pluginWsmanRunAsUserPath $runAsCredential -confirm:$false129 }} catch {{130 131 remove-item (Join-Path WSMan:\localhost\Plugin ""$pluginName"") -recurse -force132 write-error $_133 # Do not add anymore clean up code after Write-Error, because if EA=Stop is set by user134 # any code at this point will not execute.135 136 return137 }}138 }}139 140 ## Replace the SDDL with any groups or restrictions defined in the PSSessionConfigurationFile141 if($? -and $configTableSddl -and (-not $isSddlSpecified))142 {{143 $null = Set-PSSessionConfiguration -Name $pluginName -SecurityDescriptorSddl $configTableSddl -NoServiceRestart:$noRestart -Force:$force144 }}145 146 if ($? -and $shouldShowUI)147 {{148 $null = winrm configsddl ""{0}$pluginName""149 150 # if AccessMode is Disabled OR the winrm configsddl failed, we just return151 if ([System.Management.Automation.Runspaces.PSSessionConfigurationAccessMode]::Disabled.Equals($accessMode) -or !$?)152 {{153 return154 }}155 }} # end of if ($shouldShowUI)156 157 if ($?)158 {{159 # if AccessMode is Local or Remote, we need to check the SDDL the user set in the UI or passed in to the cmdlet.160 $newSDDL = $null161 $curPlugin = Get-PSSessionConfiguration -Name $pluginName -Force:$force162 $curSDDL = $curPlugin.SecurityDescriptorSddl163 if (!$curSDDL)164 {{165 if ([System.Management.Automation.Runspaces.PSSessionConfigurationAccessMode]::Local.Equals($accessMode))166 {{167 $newSDDL = ""{1}""168 }}169 }}170 else171 {{172 # Construct SID for network users173 [system.security.principal.wellknownsidtype]$evst = ""NetworkSid""174 $networkSID = new-object system.security.principal.securityidentifier $evst,$null175 176 $sd = new-object system.security.accesscontrol.commonsecuritydescriptor $false,$false,$curSDDL177 $haveDisableACE = $false178 $securityIdentifierToPurge = $null179 $sd.DiscretionaryAcl | ForEach-Object {{180 if (($_.acequalifier -eq ""accessdenied"") -and ($_.securityidentifier -match $networkSID) -and ($_.AccessMask -eq 268435456))181 {{182 $haveDisableACE = $true183 $securityIdentifierToPurge = $_.securityidentifier184 }}185 }}186 187 if (([System.Management.Automation.Runspaces.PSSessionConfigurationAccessMode]::Local.Equals($accessMode) -or188 [System.Management.Automation.Runspaces.PSSessionConfigurationAccessMode]::Remote.Equals($accessMode)) -and $haveDisableACE)189 {{190 # Add network deny ACE for local access or remote access with PSRemoting disabled.191 $sd.DiscretionaryAcl.AddAccess(""deny"", $networkSID, 268435456, ""None"", ""None"")192 $newSDDL = $sd.GetSddlForm(""all"")193 }}194 195 if ([System.Management.Automation.Runspaces.PSSessionConfigurationAccessMode]::Remote.Equals($accessMode) -and $haveDisableACE)196 {{197 # Remove the specific ACE198 $sd.discretionaryacl.RemoveAccessSpecific('Deny', $securityIdentifierToPurge, 268435456, 'none', 'none')199 200 # if there is no discretionaryacl..add Builtin Administrators and Remote Management Users201 # to the DACL group as this is the default WSMan behavior202 if ($sd.discretionaryacl.count -eq 0)203 {{204 [system.security.principal.wellknownsidtype]$bast = ""BuiltinAdministratorsSid""205 $basid = new-object system.security.principal.securityidentifier $bast,$null206 $sd.DiscretionaryAcl.AddAccess('Allow',$basid, 268435456, 'none', 'none')207 208 # Remote Management Users, Win8+ only209 if ([System.Environment]::OSVersion.Version -ge ""6.2.0.0"")210 {{211 $rmSidId = new-object system.security.principal.securityidentifier ""{2}""212 $sd.DiscretionaryAcl.AddAccess('Allow', $rmSidId, 268435456, 'none', 'none')213 }}214 215 # Interactive Users216 $iaSidId = new-object system.security.principal.securityidentifier ""{3}""217 $sd.DiscretionaryAcl.AddAccess('Allow', $iaSidId, 268435456, 'none', 'none')218 }}219 220 $newSDDL = $sd.GetSddlForm(""all"")221 }}222 }} # end of if(!$curSDDL)223 }} # end of if ($?)224 225 if ($? -and $newSDDL)226 {{227 try {{228 if ($runAsUserName)229 {{230 $runAsCredential = new-object system.management.automation.PSCredential($runAsUserName, $runAsPassword)231 $null = Set-PSSessionConfiguration -Name $pluginName -SecurityDescriptorSddl $newSDDL -NoServiceRestart:$noRestart -Force:$force -WarningAction 0 -RunAsCredential $runAsCredential232 }}233 else234 {{235 $null = Set-PSSessionConfiguration -Name $pluginName -SecurityDescriptorSddl $newSDDL -NoServiceRestart:$noRestart -Force:$force -WarningAction 0236 }}237 238 }} catch {{239 remove-item (Join-Path WSMan:\localhost\Plugin ""$pluginName"") -recurse -force240 write-error $_241 # Do not add anymore clean up code after Write-Error, because if EA=Stop is set by user242 # any code at this point will not execute.243 244 return245 }}246 }}247 248 if ($?){{249 try{{250 $s = New-PSSession -ComputerName localhost -ConfigurationName $pluginName -ErrorAction Stop251 # session is ok, no need to restart WinRM service252 Remove-PSSession $s -Confirm:$false253 }}catch{{254 # session is NOT ok, we need to restart winrm if -Force was specified, otherwise show a warning255 if ($force){{256 Restart-Service -Name WinRM -Force -Confirm:$false257 }}else{{258 $warningWSManRestart = [Microsoft.PowerShell.Commands.Internal.RemotingErrorResources]::WinRMRestartWarning -f $PSCmdlet.MyInvocation.MyCommand.Name259 Write-Warning $warningWSManRestart260 }}261 }}262 }}263 }}264}}265 266if ($null -eq $args[15])267{{268 Register-PSSessionConfiguration -filepath $args[0] -pluginName $args[1] -shouldShowUI $args[2] -force $args[3] -whatif:$args[4] -confirm:$args[5] -restartWSManTarget $args[6] -restartWSManAction $args[7] -restartWSManRequired $args[8] -runAsUserName $args[9] -runAsPassword $args[10] -accessMode $args[11] -isSddlSpecified $args[12] -configTableSddl $args[13] -noRestart $args[14]269}}270else271{{272 Register-PSSessionConfiguration -filepath $args[0] -pluginName $args[1] -shouldShowUI $args[2] -force $args[3] -whatif:$args[4] -confirm:$args[5] -restartWSManTarget $args[6] -restartWSManAction $args[7] -restartWSManRequired $args[8] -runAsUserName $args[9] -runAsPassword $args[10] -accessMode $args[11] -isSddlSpecified $args[12] -configTableSddl $args[13] -noRestart $args[14] -erroraction $args[15]273}}274";275 276 private static readonly ScriptBlock s_newPluginSb;277 278 private const string pluginXmlFormat = @"279<PlugInConfiguration xmlns='http://schemas.microsoft.com/wbem/wsman/1/config/PluginConfiguration'280 Name='{0}'281 Filename='{1}'282 SDKVersion='{12}'283 XmlRenderingType='text' {2} {6} {7} {8} {9} {10}>284 <InitializationParameters>285{3}286 287 </InitializationParameters>288 <Resources>289 <Resource ResourceUri='{4}' SupportsOptions='true' ExactMatch='true'>290{5}291 292 <Capability Type='Shell' />293 </Resource>294 </Resources>295 {11}296</PlugInConfiguration>297";298 299 private const string architectureAttribFormat = @"300 Architecture='{0}'";301 302 private const string sharedHostAttribFormat = @"303 UseSharedProcess='{0}'";304 305 private const string runasVirtualAccountAttribFormat = @"306 RunAsVirtualAccount='{0}'";307 308 private const string runAsVirtualAccountGroupsAttribFormat = @"309 RunAsVirtualAccountGroups='{0}'";310 311 private const string allowRemoteShellAccessFormat = @"312 Enabled='{0}'";313 314 private const string initParamFormat = @"315<Param Name='{0}' Value='{1}' />{2}";316 317 private const string privateDataFormat = @"<Param Name='PrivateData'>{0}</Param>";318 private const string securityElementFormat = "<Security Uri='{0}' ExactMatch='true' Sddl='{1}' />";319 private const string SessionConfigDataFormat = @"<SessionConfigurationData>{0}</SessionConfigurationData>";320 321 private string _gmsaAccount;322 private string _configTableSDDL;323 324 // true if there are errors running the wsman's configuration325 // command326 private bool _isErrorReported;327 328 #endregion329 330 #region Parameters331 332 /// <summary>333 /// Parameter used to specify the Processor Architecture that this shell targets.334 /// On a 64bit base OS, specifying a value of 32 means that the shell is configured335 /// to launch like a 32bit process (WOW64).336 /// </summary>337 [Parameter()]338 [Alias("PA")]339 [ValidateNotNullOrEmpty]340 [ValidateSet("x86", "amd64")]341 public string ProcessorArchitecture { get; set; }342 343 #endregion344 345 #region Constructors346 347 static RegisterPSSessionConfigurationCommand()348 {349 string localSDDL = GetLocalSddl();350 351 // compile the script block statically and reuse the same instance352 // every time the command is run..This will save on parsing time.353 string newPluginSbString = string.Format(CultureInfo.InvariantCulture,354 newPluginSbFormat,355 WSManNativeApi.ResourceURIPrefix, localSDDL, RemoteManagementUsersSID, InteractiveUsersSID);356 357 s_newPluginSb = ScriptBlock.Create(newPluginSbString);358 s_newPluginSb.LanguageMode = PSLanguageMode.FullLanguage;359 }360 361 #endregion362 363 #region Cmdlet Overrides364 365 /// <summary>366 /// </summary>367 /// <exception cref="InvalidOperationException">368 /// 1. Either both "AssemblyName" and "ConfigurationTypeName" must be specified369 /// or both must not be specified.370 /// </exception>371 protected override void BeginProcessing()372 {373 if (isSddlSpecified && showUISpecified)374 {375 string message = StringUtil.Format(RemotingErrorIdStrings.ShowUIAndSDDLCannotExist,376 "SecurityDescriptorSddl",377 "ShowSecurityDescriptorUI");378 throw new PSInvalidOperationException(message);379 }380 381 if (isRunAsCredentialSpecified)382 {383 WriteWarning(RemotingErrorIdStrings.RunAsSessionConfigurationSecurityWarning);384 }385 386 if (isSddlSpecified)387 {388 // Constructor call should succeed. The sddl is check in the property setter389 CommonSecurityDescriptor descriptor = new CommonSecurityDescriptor(false, false, sddl);390 SecurityIdentifier networkSidIdentifier = new SecurityIdentifier(WellKnownSidType.NetworkSid, null);391 bool networkDenyAllExists = false;392 foreach (CommonAce ace in descriptor.DiscretionaryAcl)393 {394 if (ace.AceQualifier.Equals(AceQualifier.AccessDenied) && ace.SecurityIdentifier.Equals(networkSidIdentifier) && ace.AccessMask == 268435456)395 {396 networkDenyAllExists = true;397 break;398 }399 }400 401 switch (AccessMode)402 {403 case PSSessionConfigurationAccessMode.Local:404 if (!networkDenyAllExists)405 {406 descriptor.DiscretionaryAcl.AddAccess(AccessControlType.Deny, networkSidIdentifier, 268435456, InheritanceFlags.None, PropagationFlags.None);407 sddl = descriptor.GetSddlForm(AccessControlSections.All);408 }409 410 break;411 case PSSessionConfigurationAccessMode.Remote:412 if (networkDenyAllExists)413 {414 // Remove the specific ACE415 descriptor.DiscretionaryAcl.RemoveAccessSpecific(AccessControlType.Deny, networkSidIdentifier, 268435456, InheritanceFlags.None, PropagationFlags.None);416 // If the discretionaryAcl becomes empty, add the BA and RM which is the default WinRM behavior417 if (descriptor.DiscretionaryAcl.Count == 0)418 {419 // BA420 SecurityIdentifier baSidIdentifier = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null);421 descriptor.DiscretionaryAcl.AddAccess(AccessControlType.Allow, baSidIdentifier, 268435456, InheritanceFlags.None, PropagationFlags.None);422 423 // Only for Win8+424 if (Environment.OSVersion.Version >= new Version(6, 2))425 {426 // Remote Management Users427 SecurityIdentifier rmSidIdentifier = new SecurityIdentifier(RemoteManagementUsersSID);428 descriptor.DiscretionaryAcl.AddAccess(AccessControlType.Allow, rmSidIdentifier, 268435456, InheritanceFlags.None, PropagationFlags.None);429 }430 431 // Interactive Users432 SecurityIdentifier iaSidIdentifier = new SecurityIdentifier(InteractiveUsersSID);433 descriptor.DiscretionaryAcl.AddAccess(AccessControlType.Allow, iaSidIdentifier, 268435456, InheritanceFlags.None, PropagationFlags.None);434 }435 436 sddl = descriptor.GetSddlForm(AccessControlSections.All);437 }438 439 break;440 case PSSessionConfigurationAccessMode.Disabled:441 break;442 }443 }444 445 if (!isSddlSpecified && !showUISpecified)446 {447 if (AccessMode.Equals(PSSessionConfigurationAccessMode.Local))448 {449 // If AccessMode is Local or Disabled and no SDDL specified, use the default local SDDL450 sddl = GetLocalSddl();451 }452 else if (AccessMode.Equals(PSSessionConfigurationAccessMode.Remote))453 {454 // If AccessMode is Remote and no SDDL specified then use the default remote SDDL455 sddl = GetRemoteSddl();456 }457 }458 459 // check if we have compatible WSMan460 RemotingCommandUtil.CheckRemotingCmdletPrerequisites();461 PSSessionConfigurationCommandUtilities.ThrowIfNotAdministrator();462 463 WSManConfigurationOption wsmanOption = transportOption as WSManConfigurationOption;464 465 if (wsmanOption != null)466 {467 if (wsmanOption.ProcessIdleTimeoutSec != null && !isUseSharedProcessSpecified)468 {469 PSInvalidOperationException ioe = new PSInvalidOperationException(470 StringUtil.Format(RemotingErrorIdStrings.InvalidConfigurationXMLAttribute, "ProcessIdleTimeoutSec",471 "UseSharedProcess"));472 ThrowTerminatingError(ioe.ErrorRecord);473 }474 }475 476 string pluginPath = PSSessionConfigurationCommandUtilities.GetWinrmPluginDllPath();477 pluginPath = Environment.ExpandEnvironmentVariables(pluginPath);478 if (!System.IO.File.Exists(pluginPath))479 {480 PSInvalidOperationException ioe = new PSInvalidOperationException(481 StringUtil.Format(RemotingErrorIdStrings.PluginDllMissing, RemotingConstants.PSPluginDLLName));482 ThrowTerminatingError(ioe.ErrorRecord);483 }484 }485 486 /// <summary>487 /// For each record, execute it, and push the results into the488 /// success stream.489 /// </summary>490 protected override void ProcessRecord()491 {492 WriteVerbose(StringUtil.Format(RemotingErrorIdStrings.NcsScriptMessageV, newPluginSbFormat));493 494 if (!force)495 {496 string shouldProcessAction = StringUtil.Format(RemotingErrorIdStrings.CSShouldProcessAction,497 this.CommandInfo.Name);498 string shouldProcessTarget;499 500 if (isSddlSpecified)501 {502 shouldProcessTarget = StringUtil.Format(RemotingErrorIdStrings.NcsShouldProcessTargetSDDL, Name, sddl);503 }504 else505 {506 shouldProcessTarget = StringUtil.Format(RemotingErrorIdStrings.CSShouldProcessTargetAdminEnable, Name);507 }508 509 string action = StringUtil.Format(RemotingErrorIdStrings.CSShouldProcessAction,510 this.CommandInfo.Name);511 WriteWarning(StringUtil.Format(RemotingErrorIdStrings.WinRMRestartWarning, action));512 513 if (!ShouldProcess(shouldProcessTarget, shouldProcessAction))514 {515 return;516 }517 }518 519 // Configuration file copy information.520 string srcConfigFilePath;521 string destConfigFilePath;522 523 // construct plugin config file.524 string pluginContent = ConstructPluginContent(out srcConfigFilePath, out destConfigFilePath);525 526 // Create temporary file with the content.527 string file = ConstructTemporaryFile(pluginContent);528 529 // Move the WinRM service to its own service host if the endpoint is given elevated credentials.530 if (isRunAsCredentialSpecified || RunAsVirtualAccountSpecified)531 {532 PSSessionConfigurationCommandUtilities.MoveWinRmToIsolatedServiceHost(RunAsVirtualAccountSpecified);533 }534 535 // Use the Group Managed Service Account if provided.536 if (!isRunAsCredentialSpecified && !string.IsNullOrEmpty(_gmsaAccount))537 {538 runAsCredential = PSSessionConfigurationCommandUtilities.CreateGMSAAccountCredentials(_gmsaAccount);539 }540 541 try542 {543 // restart-service winrm to make the changes effective.544 string restartServiceAction = RemotingErrorIdStrings.RestartWSManServiceAction;545 string restartServiceTarget = StringUtil.Format(RemotingErrorIdStrings.RestartWSManServiceTarget, "WinRM");546 547 string restartWSManRequiredForUI = StringUtil.Format(RemotingErrorIdStrings.RestartWSManRequiredShowUI,548 string.Create(CultureInfo.InvariantCulture, $"Set-PSSessionConfiguration {shellName} -ShowSecurityDescriptorUI"));549 550 // gather -WhatIf, -Confirm parameter data and pass it to the script block551 bool whatIf = false;552 // confirm is always true to start with553 bool confirm = true;554 PSSessionConfigurationCommandUtilities.CollectShouldProcessParameters(this, out whatIf, out confirm);555 // gather -ErrorAction parameter data and pass it to the script block. if -ErrorAction is not set, pass $null in556 object errorAction = null;557 if (Context.CurrentCommandProcessor.CommandRuntime.IsErrorActionSet)558 {559 errorAction = Context.CurrentCommandProcessor.CommandRuntime.ErrorAction;560 }561 562 ArrayList errorList = (ArrayList)Context.DollarErrorVariable;563 int errorCountBefore = errorList.Count;564 565 if (force &&566 this.Context != null &&567 this.Context.EngineHostInterface != null &&568 this.Context.EngineHostInterface.ExternalHost != null &&569 this.Context.EngineHostInterface.ExternalHost is System.Management.Automation.Remoting.ServerRemoteHost)570 {571 WriteWarning(RemotingErrorIdStrings.WinRMForceRestartWarning);572 }573 574 s_newPluginSb.InvokeUsingCmdlet(575 contextCmdlet: this,576 useLocalScope: true,577 errorHandlingBehavior: ScriptBlock.ErrorHandlingBehavior.WriteToCurrentErrorPipe,578 dollarUnder: AutomationNull.Value,579 input: Array.Empty<object>(),580 scriptThis: AutomationNull.Value,581 args: new object[] {582 file,583 shellName,584 ShowSecurityDescriptorUI.ToBool(),585 force,586 whatIf,587 confirm,588 restartServiceTarget,589 restartServiceAction,590 restartWSManRequiredForUI,591 runAsCredential?.UserName,592 runAsCredential?.Password,593 AccessMode,594 isSddlSpecified,595 _configTableSDDL,596 noRestart,597 errorAction598 });599 600 errorList = (ArrayList)Context.DollarErrorVariable;601 _isErrorReported = errorList.Count > errorCountBefore;602 }603 finally604 {605 DeleteFile(file);606 }607 608 // If the file no longer exists then re-copy the configuration file to the dest location after609 // newPluginSb script is run the file no longer exists.610 if ((srcConfigFilePath != null) && (destConfigFilePath != null) &&611 !File.Exists(destConfigFilePath))612 {613 try614 {615 File.Copy(srcConfigFilePath, destConfigFilePath, true);616 }617 catch (IOException) { }618 catch (ArgumentException) { }619 catch (NotSupportedException) { }620 catch (UnauthorizedAccessException) { }621 }622 }623 624 /// <summary>625 /// </summary>626 protected override void EndProcessing()627 {628 System.Management.Automation.Tracing.Tracer tracer = new System.Management.Automation.Tracing.Tracer();629 tracer.EndpointRegistered(this.Name, WindowsIdentity.GetCurrent().Name);630 }631 632 #endregion633 634 #region Private Methods635 636 /// <summary>637 /// </summary>638 /// <param name="tmpFileName"></param>639 /// <returns></returns>640 /// <exception cref="InvalidOperationException">641 /// 1. New shell successfully registered. However cannot delete temporary plugin file {0}.642 /// Reason for failure: {1}.643 /// </exception>644 private static void DeleteFile(string tmpFileName)645 {646 Dbg.Assert(!string.IsNullOrEmpty(tmpFileName), "tmpFile cannot be null or empty.");647 648 Exception e = null;649 try650 {651 File.Delete(tmpFileName);652 // WriteWarning(tmpFileName);653 }654 catch (UnauthorizedAccessException uae)655 {656 e = uae;657 }658 catch (ArgumentException ae)659 {660 e = ae;661 }662 catch (PathTooLongException pe)663 {664 e = pe;665 }666 catch (DirectoryNotFoundException dnfe)667 {668 e = dnfe;669 }670 catch (IOException ioe)671 {672 e = ioe;673 }674 catch (NotSupportedException nse)675 {676 e = nse;677 }678 679 if (e != null)680 {681 throw PSTraceSource.NewInvalidOperationException(RemotingErrorIdStrings.NcsCannotDeleteFileAfterInstall,682 tmpFileName,683 e.Message);684 }685 }686 687 /// <summary>688 /// </summary>689 /// <param name="pluginContent"></param>690 /// <returns></returns>691 /// <exception cref="InvalidOperationException">692 /// 1. Cannot delete temporary file {0}. Try again. Reason for failure: {1}.693 /// 2. Cannot write shell configuration data into temporary file {0}. Try again.694 /// Reason for failure: {1}.695 /// </exception>696 private static string ConstructTemporaryFile(string pluginContent)697 {698 // Path.GetTempFileName creates a temporary file whereas GetRandomFileName does not.699 string tmpFileName = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetRandomFileName()) + "psshell.xml";700 701 Exception e = null;702 // Remove the temp file if it exists.703 if (File.Exists(tmpFileName))704 {705 FileInfo destfile = new FileInfo(tmpFileName);706 if (destfile != null)707 {708 try709 {710 // Make sure the file is not read only711 destfile.Attributes &= ~(FileAttributes.ReadOnly | FileAttributes.Hidden);712 destfile.Delete();713 }714 catch (FileNotFoundException fnf)715 {716 e = fnf;717 }718 catch (DirectoryNotFoundException dnf)719 {720 e = dnf;721 }722 catch (UnauthorizedAccessException uac)723 {724 e = uac;725 }726 catch (System.Security.SecurityException se)727 {728 e = se;729 }730 catch (ArgumentNullException ane)731 {732 e = ane;733 }734 catch (ArgumentException ae)735 {736 e = ae;737 }738 catch (PathTooLongException pe)739 {740 e = pe;741 }742 catch (NotSupportedException ns)743 {744 e = ns;745 }746 catch (IOException ioe)747 {748 e = ioe;749 }750 751 if (e != null)752 {753 throw PSTraceSource.NewInvalidOperationException(RemotingErrorIdStrings.NcsCannotDeleteFile,754 tmpFileName,755 e.Message);756 }757 }758 }759 760 try761 {762 using (StreamWriter fileStream = File.CreateText(tmpFileName))763 {764 fileStream.Write(pluginContent);765 fileStream.Flush();766 }767 }768 catch (UnauthorizedAccessException uae)769 {770 e = uae;771 }772 catch (ArgumentException ae)773 {774 e = ae;775 }776 catch (PathTooLongException pe)777 {778 e = pe;779 }780 catch (DirectoryNotFoundException dnfe)781 {782 e = dnfe;783 }784 785 if (e != null)786 {787 throw PSTraceSource.NewInvalidOperationException(RemotingErrorIdStrings.NcsCannotWritePluginContent,788 tmpFileName,789 e.Message);790 }791 792 return tmpFileName;793 }794 795 private string ConstructPluginContent(out string srcConfigFilePath, out string destConfigFilePath)796 {797 srcConfigFilePath = null;798 destConfigFilePath = null;799 StringBuilder initParameters = new StringBuilder();800 801 const bool assemblyAndTypeTokensSet = false;802 803 // DISC endpoint804 if (Path != null)805 {806 ProviderInfo provider = null;807 PSDriveInfo drive;808 string filePath = SessionState.Path.GetUnresolvedProviderPathFromPSPath(Path, out provider, out drive);809 810 if (!provider.NameEquals(Context.ProviderNames.FileSystem) || !filePath.EndsWith(StringLiterals.PowerShellDISCFileExtension, StringComparison.OrdinalIgnoreCase))811 {812 string message = StringUtil.Format(RemotingErrorIdStrings.InvalidPSSessionConfigurationFilePath, filePath);813 InvalidOperationException ioe = new InvalidOperationException(message);814 ErrorRecord er = new ErrorRecord(ioe, "InvalidPSSessionConfigurationFilePath",815 ErrorCategory.InvalidArgument, Path);816 ThrowTerminatingError(er);817 }818 819 Guid sessionGuid = Guid.Empty;820 821 // Load session GUID from config file822 string scriptName;823 ExternalScriptInfo scriptInfo = null;824 Hashtable configTable = null;825 826 try827 {828 scriptInfo = DISCUtils.GetScriptInfoForFile(this.Context, filePath, out scriptName);829 configTable = DISCUtils.LoadConfigFile(this.Context, scriptInfo);830 }831 catch (RuntimeException rte)832 {833 string message = StringUtil.Format(RemotingErrorIdStrings.InvalidPSSessionConfigurationFileErrorProcessing, filePath, rte.Message);834 InvalidOperationException ioe = new InvalidOperationException(message, rte);835 ErrorRecord er = new ErrorRecord(ioe, "InvalidPSSessionConfigurationFilePath",836 ErrorCategory.InvalidArgument, Path);837 ThrowTerminatingError(er);838 }839 840 if (configTable == null)841 {842 string message = StringUtil.Format(RemotingErrorIdStrings.InvalidPSSessionConfigurationFile, filePath);843 InvalidOperationException ioe = new InvalidOperationException(message);844 ErrorRecord er = new ErrorRecord(ioe, "InvalidPSSessionConfigurationFile",845 ErrorCategory.InvalidArgument, Path);846 ThrowTerminatingError(er);847 }848 else849 {850 if (configTable.ContainsKey(ConfigFileConstants.Guid))851 {852 try853 {854 if (configTable[ConfigFileConstants.Guid] != null)855 {856 sessionGuid = Guid.Parse(configTable[ConfigFileConstants.Guid].ToString());857 }858 else859 {860 InvalidOperationException invalidOperationException = new InvalidOperationException(StringUtil.Format(RemotingErrorIdStrings.ErrorParsingTheKeyInPSSessionConfigurationFile, ConfigFileConstants.Guid, filePath));861 ThrowTerminatingError(new ErrorRecord(invalidOperationException, "InvalidGuidInPSSessionConfigurationFile", ErrorCategory.InvalidOperation, null));862 }863 }864 catch (FormatException e)865 {866 ThrowTerminatingError(new ErrorRecord(e, "InvalidGuidInPSSessionConfigurationFile", ErrorCategory.InvalidOperation, null));867 }868 }869 870 if (configTable.ContainsKey(ConfigFileConstants.PowerShellVersion))871 {872 if (!isPSVersionSpecified)873 {874 try875 {876 PSVersion = new Version(configTable[ConfigFileConstants.PowerShellVersion].ToString());877 }878 catch (ArgumentException e)879 {880 ThrowTerminatingError(new ErrorRecord(e, "InvalidPowerShellVersion", ErrorCategory.InvalidOperation, null));881 }882 catch (FormatException e)883 {884 ThrowTerminatingError(new ErrorRecord(e, "InvalidPowerShellVersion", ErrorCategory.InvalidOperation, null));885 }886 catch (OverflowException e)887 {888 ThrowTerminatingError(new ErrorRecord(e, "InvalidPowerShellVersion", ErrorCategory.InvalidOperation, null));889 }890 }891 }892 893 if (configTable.ContainsKey(ConfigFileConstants.RunAsVirtualAccount))894 {895 this.RunAsVirtualAccount = LanguagePrimitives.ConvertTo<bool>(configTable[ConfigFileConstants.RunAsVirtualAccount]);896 this.RunAsVirtualAccountSpecified = true;897 }898 899 if (configTable.ContainsKey(ConfigFileConstants.RunAsVirtualAccountGroups))900 {901 this.RunAsVirtualAccountGroups = PSSessionConfigurationCommandUtilities.GetRunAsVirtualAccountGroupsString(902 DISCPowerShellConfiguration.TryGetStringArray(configTable[ConfigFileConstants.RunAsVirtualAccountGroups]));903 }904 905 if (configTable.ContainsKey(ConfigFileConstants.GMSAAccount))906 {907 _gmsaAccount = configTable[ConfigFileConstants.GMSAAccount] as string;908 }909 910 // Get role account and group restriction SDDL from configuration table, if any.911 ErrorRecord error;912 _configTableSDDL = PSSessionConfigurationCommandUtilities.ComputeSDDLFromConfiguration(913 configTable,914 AccessMode,915 out error);916 if (error != null)917 {918 WriteError(error);919 }920 921 // Update default Sddl with any group membership requirements.922 if (string.IsNullOrEmpty(_configTableSDDL) && !this.isSddlSpecified && !string.IsNullOrEmpty(sddl))923 {924 string configGroupMemberShipACE = PSSessionConfigurationCommandUtilities.CreateConditionalACEFromConfig(configTable);925 if (!string.IsNullOrEmpty(configGroupMemberShipACE))926 {927 sddl = PSSessionConfigurationCommandUtilities.UpdateSDDLUsersWithGroupConditional(sddl, configGroupMemberShipACE);928 }929 }930 931 try932 {933 DISCUtils.ValidateAbsolutePaths(SessionState, configTable, Path);934 }935 catch (InvalidOperationException e)936 {937 ThrowTerminatingError(new ErrorRecord(e, "RelativePathsNotSupported", ErrorCategory.InvalidOperation, null));938 }939 940 try941 {942 DISCUtils.ValidateExtensions(configTable, Path);943 }944 catch (InvalidOperationException e)945 {946 ThrowTerminatingError(new ErrorRecord(e, "FileExtensionNotSupported", ErrorCategory.InvalidOperation, null));947 }948 }949 950 string destFolder = System.IO.Path.Combine(Utils.DefaultPowerShellAppBase, "SessionConfig");951 if (!Directory.Exists(destFolder))952 {953 Directory.CreateDirectory(destFolder);954 }955 956 string destPath = System.IO.Path.Combine(destFolder,957 shellName + "_" + sessionGuid.ToString() + StringLiterals.PowerShellDISCFileExtension);958 if (string.Equals(ProcessorArchitecture, "x86", StringComparison.OrdinalIgnoreCase))959 {960 string procArch = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE");961 962 if (string.Equals(procArch, "amd64", StringComparison.OrdinalIgnoreCase) ||963 string.Equals(procArch, "ia64", StringComparison.OrdinalIgnoreCase))964 {965#if CORECLR966 InvalidOperationException ioe = new InvalidOperationException(RemotingErrorIdStrings.InvalidProcessorArchitecture);967 ErrorRecord er = new ErrorRecord(ioe, "InvalidProcessorArchitecture", ErrorCategory.InvalidArgument, Path);968 ThrowTerminatingError(er);969#else970 // syswow64 is applicable only on 64 bit platforms.971 destPath = destPath.ToLowerInvariant().Replace("\\system32\\", "\\syswow64\\");972#endif973 }974 }975 976 // Return configuration file path names for later copy operation, if needed.977 // We need to copy the file again if after running Register-PSSessionConfiguration978 // removes the file which can happen if the endpoint already exists.979 srcConfigFilePath = filePath;980 destConfigFilePath = destPath;981 982 // Copy File.983 string destConfigFileDirectory = System.IO.Path.GetDirectoryName(destConfigFilePath);984 985 // The directory is not auto-created for PowerShell.986 // The call will create it or return its path if it already exists987 System.IO.Directory.CreateDirectory(destConfigFileDirectory);988 989 File.Copy(srcConfigFilePath, destConfigFilePath, true);990 991 initParameters.Append(string.Format(CultureInfo.InvariantCulture,992 initParamFormat,993 ConfigurationDataFromXML.CONFIGFILEPATH_CamelCase,994 destPath,995 Environment.NewLine));996 }997 998 if (!assemblyAndTypeTokensSet)999 {1000 if (!string.IsNullOrEmpty(configurationTypeName))1001 {1002 initParameters.Append(string.Format(CultureInfo.InvariantCulture,1003 initParamFormat,1004 ConfigurationDataFromXML.SHELLCONFIGTYPETOKEN,1005 configurationTypeName,1006 Environment.NewLine));1007 }1008 1009 if (!string.IsNullOrEmpty(assemblyName))1010 {1011 initParameters.Append(string.Format(CultureInfo.InvariantCulture,1012 initParamFormat,1013 ConfigurationDataFromXML.ASSEMBLYTOKEN,1014 assemblyName,1015 Environment.NewLine));1016 }1017 }1018 1019 if (!string.IsNullOrEmpty(applicationBase))1020 {1021 initParameters.Append(string.Format(CultureInfo.InvariantCulture,1022 initParamFormat,1023 ConfigurationDataFromXML.APPBASETOKEN,1024 applicationBase,1025 Environment.NewLine));1026 }1027 1028 if (!string.IsNullOrEmpty(configurationScript))1029 {1030 initParameters.Append(string.Format(CultureInfo.InvariantCulture,1031 initParamFormat,1032 ConfigurationDataFromXML.STARTUPSCRIPTTOKEN,1033 configurationScript,1034 Environment.NewLine));1035 }1036 1037 if (maxCommandSizeMB.HasValue)1038 {1039 initParameters.Append(string.Format(CultureInfo.InvariantCulture,1040 initParamFormat,1041 ConfigurationDataFromXML.MAXRCVDCMDSIZETOKEN,1042 maxCommandSizeMB.Value,1043 Environment.NewLine));1044 }1045 1046 if (maxObjectSizeMB.HasValue)1047 {1048 initParameters.Append(string.Format(CultureInfo.InvariantCulture,1049 initParamFormat,1050 ConfigurationDataFromXML.MAXRCVDOBJSIZETOKEN,1051 maxObjectSizeMB.Value,1052 Environment.NewLine));1053 }1054 1055 if (threadAptState.HasValue)1056 {1057 initParameters.Append(string.Format(CultureInfo.InvariantCulture,1058 initParamFormat,1059 ConfigurationDataFromXML.THREADAPTSTATETOKEN,1060 threadAptState.Value,1061 Environment.NewLine));1062 }1063 1064 if (threadOptions.HasValue)1065 {1066 initParameters.Append(string.Format(CultureInfo.InvariantCulture,1067 initParamFormat,1068 ConfigurationDataFromXML.THREADOPTIONSTOKEN,1069 threadOptions.Value,1070 Environment.NewLine));1071 }1072 1073 // Default value for PSVersion1074 if (!isPSVersionSpecified)1075 {1076 psVersion = PSVersionInfo.PSVersion;1077 }1078 1079 if (psVersion != null)1080 {1081 initParameters.Append(string.Format(CultureInfo.InvariantCulture,1082 initParamFormat,1083 ConfigurationDataFromXML.PSVERSIONTOKEN,1084 PSSessionConfigurationCommandUtilities.ConstructVersionFormatForConfigXml(psVersion),1085 Environment.NewLine));1086 1087 // Calculate MaxPSVersion from PSVersion1088 MaxPSVersion = PSSessionConfigurationCommandUtilities.CalculateMaxPSVersion(psVersion);1089 1090 if (MaxPSVersion != null)1091 {1092 initParameters.Append(string.Format(CultureInfo.InvariantCulture,1093 initParamFormat,1094 ConfigurationDataFromXML.MAXPSVERSIONTOKEN,1095 PSSessionConfigurationCommandUtilities.ConstructVersionFormatForConfigXml(MaxPSVersion),1096 Environment.NewLine));1097 }1098 }1099 1100 string securityParameters = string.Empty;1101 if (!string.IsNullOrEmpty(sddl))1102 {1103 securityParameters = string.Format(CultureInfo.InvariantCulture,1104 securityElementFormat,1105 WSManNativeApi.ResourceURIPrefix + shellName,1106 SecurityElement.Escape(sddl));1107 }1108 1109 string architectureParameter = string.Empty;1110 if (!string.IsNullOrEmpty(ProcessorArchitecture))1111 {1112 string tempValue = "32";1113 switch (ProcessorArchitecture.ToLowerInvariant())1114 {1115 case "x86":1116 tempValue = "32";1117 break;1118 case "amd64":1119 tempValue = "64";1120 break;1121 }1122 1123 architectureParameter = string.Format(CultureInfo.InvariantCulture,1124 architectureAttribFormat,1125 tempValue);1126 }1127 1128 string sharedHostParameter = string.Empty;1129 if (isUseSharedProcessSpecified)1130 {1131 sharedHostParameter = string.Format(CultureInfo.InvariantCulture,1132 sharedHostAttribFormat, UseSharedProcess.ToString()1133 );1134 }1135 1136 string runAsVirtualAccountParameter = string.Empty;1137 string runAsVirtualAccountGroupsParameter = string.Empty;1138 if (RunAsVirtualAccount)1139 {1140 runAsVirtualAccountParameter = string.Format(CultureInfo.InvariantCulture,1141 runasVirtualAccountAttribFormat, RunAsVirtualAccount.ToString()1142 );1143 1144 // Include virtual account groups if any.1145 if (!string.IsNullOrEmpty(RunAsVirtualAccountGroups))1146 {1147 runAsVirtualAccountGroupsParameter = string.Format(CultureInfo.InvariantCulture,1148 runAsVirtualAccountGroupsAttribFormat, RunAsVirtualAccountGroups);1149 }1150 }1151 1152 string allowRemoteShellAccessParameter = string.Empty;1153 switch (AccessMode)1154 {1155 case PSSessionConfigurationAccessMode.Disabled:1156 allowRemoteShellAccessParameter = string.Format(CultureInfo.InvariantCulture,1157 allowRemoteShellAccessFormat, false.ToString());1158 break;1159 case PSSessionConfigurationAccessMode.Local:1160 case PSSessionConfigurationAccessMode.Remote:1161 allowRemoteShellAccessParameter = string.Format(CultureInfo.InvariantCulture,1162 allowRemoteShellAccessFormat, true.ToString());1163 break;1164 }1165 1166 StringBuilder sessionConfigurationData = new StringBuilder();1167 1168 if (modulesToImport != null && modulesToImport.Length > 0)1169 {1170 sessionConfigurationData.Append(string.Format(CultureInfo.InvariantCulture,1171 initParamFormat,1172 PSSessionConfigurationData.ModulesToImportToken,1173 PSSessionConfigurationCommandUtilities.GetModulePathAsString(modulesToImport),1174 string.Empty));1175 }1176 1177 if (sessionTypeOption != null)1178 {1179 // TODO: This should probably be a terminating exception for Win81180 string privateData = this.sessionTypeOption.ConstructPrivateData();1181 if (!string.IsNullOrEmpty(privateData))1182 {1183 sessionConfigurationData.Append(string.Format(CultureInfo.InvariantCulture, privateDataFormat, privateData));1184 }1185 }1186 1187 if (sessionConfigurationData.Length > 0)1188 {1189 string sessionConfigData = string.Format(CultureInfo.InvariantCulture,1190 SessionConfigDataFormat,1191 sessionConfigurationData);1192 string encodedSessionConfigData = SecurityElement.Escape(sessionConfigData);1193 initParameters.Append(string.Format(CultureInfo.InvariantCulture,1194 initParamFormat,1195 ConfigurationDataFromXML.SESSIONCONFIGTOKEN,1196 encodedSessionConfigData,1197 string.Empty));1198 }1199 1200 if (transportOption == null)