Quick Guide to PowerShell Remoting (for SharePoint stuff…)

Lately I have been doing quite a bit of PowerShell remoting (mostly in a SharePoint context) and while it is surprisingly easy and useful there are a few hoops I’ll detail here.

I have been a fan of PowerShell ever since TechEd ’06 in Barcelona where some young chap eloquently introduced PowerShell. Everyone in the audience understood the potential.

Since then it is now so pervasive that I don’t have to waste time to argue it’s role and prevalence among scripting languages – and the remoting part once again is head and shoulders over the alternatives (even SSH on the unixes).

For remoting in a SharePoint context, there are 3, perhaps 4 steps, for other purposes you wouldn’t hurt yourself to go through the same.

Note: Everything in this post must be executed within an administrative PowerShell console.

Note: There are about a gazillion settings and variations that I’ve skipped; this is how I normally do it.

Step 1: Enable PS Remoting

This one is dead simple.

On the clients (the servers that you are remoting to) execute

Enable-PSRemoting

In a PowerShell shell (in admin mode) – just press return for every confirmation prompt; the defaults are sensible (or add “-force”).

Step 2: Set Sensible Memory Limits

By default each remoting session will have a cap of 150 MB of memory assigned to it. After that you’ll get a more or less random exception from the remoting session; it may be really hard to figure out what went wrong.

When you work with SharePoint you can easily spend 150 MB if you iterate over a number of SPWebs or SPSites. It may not even be possible to limit your consumption by disposing explicitly (use start-spassignment for that) if you actually need to iterate it all (Side-note: When the session ends so does all allocated objects – whether you Dispose them or not doesn’t matter).

Let’s face it these are often expensive scripts with a lot of work to do.

The fix is simple (and in my opinion safe). On the clients execute:

Set-item wsman:\localhost\shell\MaxMemoryPerShellMB 1024

Which will set the limit to 1 GB.

Long explanation here.

Step 3: Disable UAC

If you need to do any SharePoint or IIS administration (or a hundred other tasks) you need your script to run with Administrative rights.

The PowerShell remote process does not request administrative rights from windows – it’ll just use whatever is assigned to it.

Before you accuse me of disabling all security take a good long read at this article from Microsoft; they actually do recommend to disable UAC on servers provided that you do not use your servers for non-admin stuff (that is NO Internet browsing!).

To test whether or not UAC is enabled start a PowerShell console (simply left click the powershell icon). Does it say “Administrator:…” in the title? If yes then UAC is disabled and you are good to go.

There are at least two places to fiddle with the UAC:

  1. You can go to Control Panel / User Account Control Settings to change when you see the notifications boxes. This will NOT help you here – it is only the notification settings not the feature itself
  2. You need to go to the MMC / Local Policy Editor to disable it:
    1. Run “MMC”
    2. Choose “Add/remove snap-in”
    3. Choose “Group Policy Object”
    4. Choose “Local Computer”
    5. Follow the picture below and set the “Run all administrators in Admin Approval mode” to disabled (Note: “Admin Approval Mode” is UAC)

      Disable UAC for Admins

      Disable UAC

    6. Reboot the server
    7. TEST that UAC is disabled by starting a PowerShell and check that the title reads “Administrator:…”

You should take a step back here and ask your local sys admin whether this is a policy enforced by him or whether or not it should be. He/She can create a new policy that targets specific servers to disable UAC.

Usage and Test

Finally try it!

To enter an interactive shell execute (from the controller)

Execute:

    Enter-PSSession –computername $clientComputerName

If all goes well you’ll see that the prompt changes a bit and every command is now executed remotely. Do a “dir” and check that you see the remote server’s files and not the local ones.

Type “exit” to return to the controller.

If you are going cross domains you’ll receive an error, execute step 4 (below) in that case.

To execute a command with arguments

To execute a script (and store the pipeline in $output):

$output = Invoke-Command -ComputerName $clientComputerName -FilePath “. \ScriptToExecute.p1” -ArgumentList ($arg1, $arg2, $arg3)

Note that the script file (“ScriptToExecute.ps1”) is local to the controller and WinRM will handle the mundane task of transferring it to the client. The script is executed remotely and therefore you cannot reference other scripts as they are not transferred as well.

To execute a script block:

$output = Invoke-Command -ComputerName $clientComputerName -scriptblock { get-childitem “C:\” }

And you can of course pass arguments to your scriptblock and combine it in a hundred different ways.

Warning: Remember the context

The remote sessions are new PowerShell sessions; whatever information/variables you need you must either pass as arguments or embed within a scriptblock.

You can pass simple serializeable objects back to the controller on the pipeline, but it will not work to pass COM/WMI/SharePoint objects back.

Step 4: (Optional) Going Cross Domain?

By default PowerShell remoting will connect to the client computer and automatically pass the credentials of the current user to the client computer. That is normally what you want and ensures that you need no credentials prompt.

However that only works for servers within the same domain as the user. If you are crossing domain boundaries – AD trust or not – you need to do something more (before jumping through hoops do test it first to make sure that this is required for you)

Again, there are many options but the one with the least configuration hassles is:

  1. Add the client servers to the controller servers list of trusted hosts:set-item wsman:localhost\client\trustedhosts -value $serverList -forcewhere $serverList is a comma separated string of computernames (I use FQDN names).
  2. Pass explicit credentials to the remoting commands

    $c = Get-Credential

    Enter-PSSession -ComputerName $clientComputerName -Credential $c

    … and it should work. There are a million details regarding forests, firewalls, etc. I’ll not go into here.

(Other options are Kerberos, SSL channels, …)

Advertisements

About Søren Nielsen
Long time SharePoint Consultant.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: