Configuring PowerShell for Remoting – Part 1

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

PowerShell v2 introduces a new capability to manage systems in your organization remotely.  We directly support hosting PowerShell in either WinRM service or IIS. In this blog I will talk about WinRM service hosting and follow up with IIS Hosting in my next blog.


I want to touch upon some basic naming conventions. The cmdlets used to talk with a remote system are given a noun “PSSession” like New-PSSession (to create a persisting remote session), Remove-PSSession (to disconnect from an existing session), Get-PSSession (get active/inactive sessions in this PowerShell instance). The cmdlets used to configure a session (on the remote system) are given the noun, naturally, “PSSessionConfiguration” like Register-PSSessionConfiguration etc.


Hosting in WinRM service


You want to enable this if you want to remotely administer a system in your organization like, but not limited to, “Adding new users”, “Applying Patches”, “Inventory Management” etc. You need WinRM 2.0 CTP3 as described in our CTP3 release blog.


To create a new Session Configuration with WinRM service, run the following command:


PS C:\temp\oob> Register-PSSessionConfiguration PS_CTP3


   WSManConfig: Microsoft.WSMan.Management\WSMan::localhost\Plugin


Name                      Type                 Keys


—-                      —-                 —-


PS_CTP3                   Container            {Name=PS_CTP3}


 


“Restart WinRM service”


WinRM service need to be restarted to make the changes effective. Do you want to run the command


“restart-service winrm”?


[Y] Yes  [N] No  [S] Suspend  [?] Help (default is “Y”): y


 


Configuring a session configuration is as simple as that J As you notice WinRM service needs to be restarted to make our new session configuration effective. Of course, you can use –Force to not get prompted.


To connect to this session remotely use New-PSSession (nsn), Invoke-Command (icm), Enter-PSSession (etsn). I will show an example using ICM here:


PS F:\> icm kriscv-jhoom -ConfigurationName PS_CTP3 { “PowerShell CTP3 rocks!!”}


PowerShell CTP3 rocks!!


 


You can use –StartupScript, -SecurityDescriptorSDDL and other parameters of Register/Set-PSSessionConfiguration cmdlets to run initialization scripts, provide access permissions to a session configuration etc.


By default when you install PowerShell CTP3, we create a session configuration named Microsoft.PowerShell with WinRM service. Since PowerShell is secure by default, the session configuration Microsoft.PowerShell is registered with an SDDL that denies access to everyone. The take away point here is that when you install PowerShell (and WinRM 2.0 CTP3) everything is in place to do remote management except for access permissions. We encourage Administrators to carefully evaluate whom to give remote access.


To simplify configuration, we have created a cmdlet “Enable-PSRemoting” to enable access (by default to Administrators group) to all PowerShell based session configurations.


I personally love the StartupScript concept and want to provide few cool features here. It opens doors to number of scenarios. Basically StartupScript should be treated as the profiler script for the session configuration. This is the first command that gets run on the remote machine before the client is notified. Being the first command to run, an Admin can use this powerful feature to restrict what a remote user can do with a session configuration. A user has access to some 271 cmdlets in a default PowerShell session. A remote machine administrator can choose to provide access to only few cmdlets if he/she wants to. Let’s see this in action.


PS C:\temp> gc .\ps_ctp3_startupscript.ps1


# This is PS_CTP3 session configuration’s startup script


 


# Identify commands you want remote users to have access to


$commands = @(“get-command”,”get-service”,”get-process”)


 


get-command | ? { $commands -notcontains $_.Name } | % { $_.Visibility = “Private” }


$ExecutionContext.SessionState.LanguageMode=”NoLanguage”


 


PS C:\temp> register-PSSessionConfiguration ps_ctp3 -StartupScript C:\temp\ps_ctp3_startupscript.ps1


 -f


 


   WSManConfig: Microsoft.WSMan.Management\WSMan::localhost\Plugin


 


Name                      Type                 Keys


—-                      —-                 —-


ps_ctp3                   Container            {Name=ps_ctp3}


 


The PS_CTP3_StartupScript.ps1 has the following logic:


(a)    Makes only “get-command”,”get-service”,”get-process” visible


(b)   Sets the Language Mode to NoLanguage. We will discuss more about Language Modes later but it is suffice to say that in NoLanguage Mode language elements like ScriptBlocks evaluation, Variable deferencing, Method execution, loops, if block etc are not possible. Only cmdlets can be executed.


The following various examples depict the behavior:


PS F:\> #Create a persisting session


PS F:\> $s = nsn kriscv-jhoom -ConfigurationName PS_CTP3


PS F:\>


PS F:\> # Check what all I can do with this session


PS F:\> icm $s { get-command }


 


CommandType     Name                  Definition           PSComputerName


———–     —-                  ———-           ————–


Cmdlet          Get-Command           Get-Command [[-Ar… kriscv-jhoom


Cmdlet          Get-Process           Get-Process [[-Na… kriscv-jhoom


Cmdlet          Get-Service           Get-Service [[-Na… kriscv-jhoom


 


 


PS F:\> # I cannot harm the remote machine kriscv-jhoom


PS F:\> icm $s { while(1) { } }


The syntax is not supported by this runspace. This might be because it is in no


-language mode.


    + CategoryInfo          : ParserError: ( while(1) { } :String) [], ParseEx


   ception


    + FullyQualifiedErrorId : ScriptsNotAllowed


 


PS F:\> # however i can execute the command i have access to


PS F:\> icm $s { get-process powershell }


 


Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessNam PSComputer


                                                          e          Name


——-  ——    —–      —– —–   ——     — ———- ———-


   1162     114    78424      87244   224     9.53   8532 powershell kriscv-…


 


 


PS F:\>


 


Notice how my startup script blocked access to dangerous commands like while(1) { }. If this were allowed a hacker can easily consume my systems CPU resources.


I hope all this makes sense to you.  The beauty of this is you don’t need to learn any complex constructs. Whatever you learnt with PowerShell v1.0 are still relevant here and last but not the least your scripts/cmdlets (written using PowerShell v1.0) can be easily made available to  users remotely.


With this I will leave you to download CTP3 and explore yourself. As always we appreciate any of your feedback.


Have a safe and happy Christmas!!


Krishna Vutukuri [MSFT]


Windows PowerShell Team


 


This posting is provided AS IS with no warranties.