Configuring PowerShell for Remoting – Part 2 (Fan-In)


The features discussed in this blog post depend on PowerShell CTP3 release. Details about PowerShell CTP3 can be found at http://blogs.msdn.com/powershell/archive/2008/12/23/early-christmas-present-from-powershell-team-community-technology-preview-3-ctp3-of-windows-powershell-v2.aspx


The Part 1 of this series concentrated on configuring PowerShell remoting through WinRM service. In this blog post, I will talk about configuring PowerShell through IIS, which we call as Fan-In.


The WinRM service based PowerShell remoting is targeted for those users who want to administer/manage a machine(s) (or an asset on the machine) remotely.


The IIS service based PowerShell remoting is targeted at Cloud based applications like Hosted Exchange Service, Hosted SQL Services, Hosted SharePoint services etc. In this model, the application will typically divide its services into various roles and assign users (based on credentials etc) to each role. The following example will talk briefly about the scenario:


Example:  Let’s say Microsoft  Exchange Online services (MEOS)  is providing Mailbox hosting on the cloud to enterprises. Lets say Contoso and Fabrikam enterprises bought this cloud based Mailbox hosting from MEOS. In this model, an Adminstrator from Contoso can manage only his enterprise mailboxes. A less privileged user from Contoso can manage only his particular box. In this example we saw 2 roles: an Enterprise Admin, a Less Privileged User.


 PowerShell based remoting enables the automation of management tasks in this scenario remotely!! For example, as an Enterprise Admin (of Contoso) I can remotely create 1000’s of mailboxes for my organization in a scriptable/automatable way. This eliminates the painful task of creating each mailbox individually using UI (a.k.a browser)


To achieve this scenario, the hosted application (MEOS in this example) has to configure PowerShell/WinRM in the following way (on Windows Server 2008+):


1.       Make sure you installed CTP3 of PowerShell and WinRM


2.       Install IIS (7.0) and other required roles


a.       ocsetup.exe IIS-WebServerRole;WAS-WindowsActivationService;IIS-WebServerManagementTools;IIS-ManagementConsole;WAS-ConfigurationAPI;IIS-BasicAuthentication;IIS-WindowsAuthentication;IIS-DigestAuthentication /quiet /norestart


b.      ocsetup.exe IIS-ClientCertificateMappingAuthentication;IIS-IISCertificateMappingAuthentication;IIS-URLAuthorization;IIS-RequestFiltering;IIS-IPSecurity /quiet /norestart


                ie., we are installing the following IIS roles: “IIS-WebServerRole “, “WAS-WindowsActivationService”, “IIS-WebServerManagementTools”, “IIS-ManagementConsole”, “WAS-ConfigurationAPI”,”IIS-BasicAuthentication”,”IIS-WindowsAuthentication”,”IIS-DigestAuthentication”,”IIS-ClientCertificateMappingAuthentication”, “IIS- IISCertificateMappingAuthentication”,”IIS-URLAuthorization”,”IIS-RequestFiltering”,”IIS-IPSecurity”


The various authentication roles are not mandatory. Depending on your Authentication design you may choose to not install the Authentication roles that you do not need.


3.       Configure the HTTPS listener with a valid certificate


Although a HTTP based endpoint may be created for you Fan-In service, we recommend using HTTPS for security reasons. Also use a certificate issued by a valid certificate authority.


 


You can use makecert.exe utility to create a self signed certificate (for testing purposes).  For example, I used the following command (from an elevated command prompt) to create a test certificate for my testing purposes:


D:\temp\MakeCert.exe -pe -n “CN=442635F10-11AD.STBTEST.MICROSOFT.COM” -eku 1


.3.6.1.5.5.7.3.1 -ss my -sr localMachine -sky exchange -r


4.       Configure IIS site with WSMan. The following steps adds a site with name “WSMan_PS_Fanin” and port 443:


(a)    Copying wsmanconfig_schema.xml file to inetsrv\config\schema directory


copy $env:windir\system32\wsmanconfig_schema.xml $env:windir\system32\inetsrv\config\schema\wsmanconfig_schema.xml


 


(b)   Backup IIS Config. This is as a precautionary safety measure.


& “$env:windir\system32\inetsrv\appcmd.exe” add BACKUP WSMan_PS_Fanin


 


(c)    Stop and Start Default  App pool


 & “$env:windir\system32\inetsrv\appcmd.exe” stop APPPOOL /apppool.name:DefaultAppPool


 & “$env:windir\system32\inetsrv\appcmd.exe” start APPPOOL /apppool.name:DefaultAppPool


(d)   Register WSMan IIS Configuration. You need to add the following line to “$env:windir\system32\inetsrv\config\applicationHost.config” file under “<sectionGroup name =”system.webServer”>” section group.


<section name=”system.management.wsmanagement.config” overrideModeDefault=”Allow” />


If you want to automate this process download IIS’s PowerShell snapin and use IIS-PowerShell cmdlets


 


(e)   Register WSMan IIS Module


 & “$env:windir\system32\inetsrv\appcmd.exe” install module /name:WSMan


 /image:”$env:windir\system32\wsmsvc.dll” /add:false


 


(f)     Create a directory for the site


md “$env:systemdrive\inetpub\WSMan_PS_Fanin”


 


(g)    Create a Web.Config file in the just created directory (look at the end of the blog for a sample content)


 


(h)   Setup Website. The following steps create a site, setup appropriate bindings for authentication, and bind the site to port 443. You may want to change all (or some) of these things as per your needs.


 


               # Create the site


& “$env:windir\system32\inetsrv\appcmd.exe” add site /name:”WSMan_PS_Fanin” /id:”10″ /bindings:https://*:443 /physicalPath:”$env:systemdrive\inetpub\wwwroot”


              


              # Create the app within the site


 & “$env:windir\system32\inetsrv\appcmd.exe” add app /site.name:”WSMan_PS_Fanin” /path:”/WSMan_PS_Fanin” /physicalPath:”$env:systemdrive\inetpub\WSMan_PS_Fanin”


 


               # unlock auth sections


& “$env:windir\system32\inetsrv\appcmd.exe” unlock config -section:access


 


 & “$env:windir\system32\inetsrv\appcmd.exe” unlock config -section:anonymousAuthentication


 


& “$env:windir\system32\inetsrv\appcmd.exe” unlock config -section:basicAuthentication


 


& “$env:windir\system32\inetsrv\appcmd.exe” unlock config -section:windowsAuthentication


 


# set required authentications for the new site


 & “$env:windir\system32\inetsrv\appcmd.exe” set config “WSMan_PS_Fanin/WSMan_PS_Fanin”  /section:access /sslflags:Ssl


 


 & “$env:windir\system32\inetsrv\appcmd.exe” set config “WSMan_PS_Fanin/WSMan_PS_Fanin”  /section:anonymousAuthentication /enabled:false


 


 & “$env:windir\system32\inetsrv\appcmd.exe” set config “WSMan_PS_Fanin/WSMan_PS_Fanin”  /section:basicAuthentication /enabled:true


 


& “$env:windir\system32\inetsrv\appcmd.exe” set config “WSMan_PS_Fanin/WSMan_PS_Fanin”  /section:windowsAuthentication /enabled:true


 


# delete and set new Certificate with the ip-port. You need the certificate thumbprint


# of the certificate you created using makecert utility.


netsh http delete sslcert ipport=0.0.0.0:443


 


netsh http add sslcert ipport=0.0.0.0:443 certhash=<fill cert thumb print here>    ‘appid={4dc3e181-e14b-4a21-b022-59fc669b0914}’ certstorename=MY


 


Hint: I used the following to get the cert thumb print I just created.


 


PS D:\> dir cert:\LocalMachine\my


 


    Directory: Microsoft.PowerShell.Security\Certificate::LocalMachine\my


 


Thumbprint                                Subject


———-                                           ——-


9734CE0AD8625E33218ADD488F641CBB107427A3  CN=442635F10-11AD.STBTEST.MICROSOF…


62CFE56EFFB3C6E702ED576475F55EFF0220C441  CN=442635F10-11AD.stbtest.microsof…


1EA7ECD5FD4BF46E018EA28F4EBDA9265C8E4BB2


 


# Enable WSMan on the new app (you need to unlock the section before doing this)


 & “$env:windir\system32\inetsrv\appcmd.exe” unlock config -section:”system.webserver/modules”


 


& “$env:windir\system32\inetsrv\appcmd.exe” add module /name:”WSMan” /app.name:”WSMan_PS_Fanin/WSMan_PS_Fanin”


 


# start the Default AppPool and the site


& “$env:windir\system32\inetsrv\appcmd.exe” start APPPOOL /apppool.name:DefaultAppPool


& “$env:windir\system32\inetsrv\appcmd.exe” start site WSMan_PS_Fanin


 


Thats it!! Now our Application is ready to service client requests. You can use StartupScript or a PSSessionConfiguration to customize runspaces for each incoming client.


 


You can connect to the endpoint and invoke commands from a client using the same “New-PSSession”,”Invoke-Command”,”Enter-PSSession” cmdlets:


 


PS C:\> $env:computername


KRISCV-LH


PS C:\> $s = new-pssession -connectionuri https://442635F1011AD.STBTEST.MICROSOFT.COM:443/WSMan_PS_Fanin -cred stbtest\mspuser -SessionOption (New-WSManSessionOption -SkipCACheck -SkipCNCheck)


PS C:\> invoke-command $s { $env:computername }


442635F10-11AD


PS C:\>


 


Notice I am accessing the endpoint that we just created from a different machine!! Since my endpoint is listening on a https port using a test signed certificate I am telling the client to skip cert related checks using New-WSMananSessionOption cmdlet.


 


All the above mentioned steps can be easily automated. We did not ship a cmdlet to do this as this is not a common scenario and also IIS and related modules are not installed by default. I will write and upload a small PowerShell module which will automate all these steps.


 


The hosted application provider can customize the sessions of each incoming client using the startupscript or PSSessionConfiguration initialization parameters described below.


 


######################## Web.Config file #########################


<?xml version=”1.0″ encoding=”UTF-8″?>


<configuration>


  <system.webServer>


    <system.management.wsmanagement.config>


      <PluginModules>


        <OperationsPlugins>


          <Plugin Name=”PowerShellplugin” Filename=”%windir%\system32\pwrshplugin.dll” SDKVersion=”1″ XmlRenderingType=”text”>


           <InitializationParameters>


                <!– See the explanation of this and other parameters below–>


                <Param Name=”PSVersion” Value=”2.0″ />


            </InitializationParameters>


              <Resources>


                <Resource ResourceUri=”http://schemas.microsoft.com/powershell/Microsoft.PowerShell” SupportsOptions=”true”>


                <Capability Type=”Shell” />


                </Resource>


               </Resources>


          </Plugin>                  


        </OperationsPlugins>


      </PluginModules>


    </system.management.wsmanagement.config>


        <security>


            <access sslFlags=”Ssl” />


            <authentication>


                <anonymousAuthentication enabled=”false” />


                <basicAuthentication enabled=”true” />


                <windowsAuthentication enabled=”true” />


            </authentication>


        </security>


        <modules>


            <add name=”WSMan” />


        </modules>


  </system.webServer>


</configuration>


##################################################################


 


Initialization Parameters Section


 


As discussed earlier PowerShell remoting uses WSMan for network transport. The web.config file is parsed by IIS and WSMan. WSMan gives whatever data that is under   <InitializationParameters> section to PowerShell. This section can contain only Name, Value pairs as showed in the web.config file above. The following Name(s) are understood by PowerShell:


 












































Name


Value


Description


PSVersion


2.0


This is mandatory and value must be 2.0 for Powershell V2 release


StartupScript


<Full path of Script To execute>


Environment Variables can be used. This specifies the script to execute right after Runspace is created


PSSessionThreadOptions


Default or UseNewThread or ReuseThread or UseCurrentThread


Read PSThreadOptions Enum document for the behavior. Default is “UseCurrentThread”


PSSessionThreadApartmentState


STA or MTA or Unknown


See Runspace.ApartmentState for explanation


PSMaximumReceivedObjectSizeMB


<double>


PowerShell works with serialized Objects and this is used to limit the object size. This is to protect server from malicious clients sending huge deserialized object. The default is 10 (ie., 10MB)


PSMaximumReceivedDataSizePerCommandMB


<double>


This restricts the amount of data a command can expect as input from a remote client. The default is 50 (ie., 50MB)


AssemblyName


< assembly Name> or <Full Qualified assembly name if it is in GAC>


Used to provide customized InitialSessionState (Runspace Configuraiton) depending on the user connecting in


PSSessionConfigurationTypeName


<NameSpace Qualified type name>


This type is loaded to get the InitialSessionState. This type must derive from System.Management.Automation.Remoting.PSSessionConfiguration


ApplicationBase


<Fully qualified path>


Environment Variables can be used. This specifies the application base to use for assembly loading


 


Example PSSessionConfigurationType


 


******************************** ConfigProvider.cs ************************************


using System.Management.Automation;


using System.Management.Automation.Runspaces;


using System.Management.Automation.Remoting;


 


namespace MyCompany.MyApp


{


     /// <summary>


     /// Provides Default InitialSessionState.


     /// </summary>


    internal sealed class MyAppConfiguration : PSSessionConfiguration


    {


        /// <summary>


        ///


        /// </summary>


        /// <param name=”userPrincipal”></param>


        /// <returns></returns>


        public override InitialSessionState GetInitialSessionState(PSPrincipal userPrincipal)


        {


            return InitialSessionState.CreateDefault();


        }


    }


}


***********************************************************************************


Try it out and let us know what you think.


Thanks,


Krishna Vutukuri


Windows PowerShell Development Team


 


This posting is provided “AS IS” with no warranties.