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

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

  • Comments 6

The features discussed in this blog post depend on PowerShell CTP3 release. Details about PowerShell CTP3 can be found at

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

. -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 /

 & "$env:windir\system32\inetsrv\appcmd.exe" start APPPOOL /

(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="" 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 /"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=


netsh http add sslcert ipport= 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...



# 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" /"WSMan_PS_Fanin/WSMan_PS_Fanin"


# start the Default AppPool and the site

& "$env:windir\system32\inetsrv\appcmd.exe" start APPPOOL /

& "$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


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 }


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"?>






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


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

                <Param Name="PSVersion" Value="2.0" />



                <Resource ResourceUri="" SupportsOptions="true">

                <Capability Type="Shell" />








            <access sslFlags="Ssl" />


                <anonymousAuthentication enabled="false" />

                <basicAuthentication enabled="true" />

                <windowsAuthentication enabled="true" />




            <add name="WSMan" />






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:







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


<Full path of Script To execute>

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


Default or UseNewThread or ReuseThread or UseCurrentThread

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


STA or MTA or Unknown

See Runspace.ApartmentState for explanation



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)



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


< 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


<NameSpace Qualified type name>

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


<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.


Krishna Vutukuri

Windows PowerShell Development Team


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


Leave a Comment
  • Please add 7 and 2 and type the answer here:
  • Post
  • PingBack from

  • Very cool I've been waiting to see how to do this :)

    Couple of suggestions

    1) Add Start /Wait ocsetup ....

    so people will know when Setup has completed

    2) For these of us with out a real certificate provider you need change how Krishna has done this otherwise you'll get a TrustError given the self-signed certificate in not autmoatically trusted.

    3) Start slow and check each step i.e does http work then https, ...

    4) If everthing works fin $PID will be the same number for all sessions

    & ".\MakeCert.exe" -pe -n "CN=<common name>" -eku -ss my -sr localMachine -sky exchange -r  wsman.cer <<< this is important for the next step

    & ".\CertMgr.exe"  /Add wsman.cer /s /r localmachine root    

    Lastly I'm definitely no Web Master however here are the steps for doing this using the IIS Snapin. I was never able to get Set-WebConfigurationProperty to work and have asked on the IIS Snapin forum so these need to currenly be manually done

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

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

    ## the certificate should be put in the Trusted Root otherwise Get-WebURL and WSMan will fail with a Trust Error

    & ".\MakeCert.exe" -pe -n "CN=<common name>" -eku -ss my -sr localMachine -sky exchange -r  wsman.cer

    & ".\MakeCert.exe" -pe -n "CN=q" -eku -ss my -sr localMachine -sky exchange -r  c:wsman.cer

    ## now add the certificate to the trusted root otherwise you get a SendError or TrustFailure

    & ".\CertMgr.exe"  /Add wsman.cer /s /r localmachine root    

    ## Create the folder that will conatin the WSMan website

    md "$env:systemdrive\inetpub\WSMan_PS_Fanin"

    ## Setup the site for HTTP only (for testing) and verify the basic web state

    New-WebAppPool WSMan_PS_Fanin

    New-WebSite -Name WSMan_PS_Fanin -PhysicalPath "$env:systemdrive\inetpub\WSMan_PS_Fanin" -Port 82 -ApplicationPool WSMan_PS_Fanin    

    Set-Conent "$env:systemdrive\inetpub\WSMan_PS_Fanin\test.htm" 'hello world'

    Get-WebUrl -Url http://q:82/test.htm -Content

    ## Now setup for HTTPS and verify the Certificate and Trust for this site

    netsh http delete sslcert ipport=

    netsh http add sslcert ipport= certhash=<fill cert thumb print here>    'appid=<valid guid goes here> certstorename=MY

    Set-ItemProperty -Path IIS:\Sites\WSMan_PS_Fanin -Name Bindings -Value @{Protocol='https';BindingInformation=":443:"}

    Dir IIS:\SslBindings

    Get-WebUrl -Url https://q:/test.htm -Content

    ## Now that we have verified that the site can accept HTTPS traffic without errors setup WSMan

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

    New-WebGlobalModule -Name WSMan -Image "$env:windir\system32\wsmsvc.dll"

    ## Add this as Krishna says above


       <section name="" overrideModeDefault="Allow" />

    ## Set the following configuration sections to "Allow" by hand




        Basic, Windows

    Rather than set the Site specific settings in the applicationconfig file Copy the web.config above to your site folder

  • This is great. I was able to get up and running and specify a startup.ps1 script as a StartupScrit in web.config. However, when I try to lock it down by setting certain commands to private, I get the following error when I try to enter the session

    Enter-PSSession : Enter-PSSession failed because the remote Session does not provide commands that it needs.

    Here's my startup.ps1 script

    $commands = get-command -verb get,where,sort,group,out,export,convertTo |

               foreach-object {$_.Name}

    get-command | where-object { $commands -notcontains $_.Name } |

                  foreach-object { $_.Visibility = "Private" }


    Any ideas would be very much appreciated



  • Andy, you get an error because your startup script  doesn't load three of required cmdlets - Exit-PSSession, Measure-Object, and Select-Object.

    $RequiredCommands = @(









  • We are finally moving to a PS remote administration workflow, is there a comprehensive document that explains the setup requirements, permissions, etc?

    Thanks for any help you can provide.

  • Richard Siddaway wrote some very good posts on PowerShell remoting.  I recommend starting with these:


    Paul Higinbotham [MSFT]

    Windows PowerShell Development

Page 1 of 1 (6 items)