Thursday, July 14, 2011

Setup Windows Remote Management and PSSession

Executing remote commands in Powershell 1 required a good deal of knowledge of powershell and the use of SysInternals' PsExec tool. It had it's drawbacks and inherent insecurites. Perhaps you wanted to remote deploy a SharePoint 2007 package from a TFSBuild script. If the Build Service account doesn't have access to the server or to deploy to SharePoint, psexec needs to have credentials in the command. It works, but not secure. Depending on how much access you have to the build environment, it might be the only option. Using PsExec to deploy packages to SharePoint 2010 throws errors and all attempts thus far have failed. Below is an example adapted from Lee Holmes:
$expression = "C:\SharePointDeploy\Deploy.ps1";
$commandBytes = [System.Text.Encoding]::Unicode.GetBytes($expression)
$encodedCommand = [Convert]::ToBase64String($commandBytes)
psexec /acceptEula /username domain\SPServiceAcct /password s0meP@ssw0rd \\server cmd /c "echo . | powershell -EncodedCommand $encodedCommand"
cmd /c pause
We can use the Windows Remote Management (WinRM) to enable a better, faster remoting experience. Both computers must be set up to allow WinRM. First set up the "remote" server:
Enable-PSRemoting -force
Enable-WSManCredSSP –role Server -force
Set-Item WSMan:\localhost\Shell\MaxMemoryPerShellMB 1000
Before we get the client setup we need to setup the client computer, WinRM cannot be setup when connected to public networks or have network adapters set to public category. Continue after the below script if this doesn't apply. If this is the case, those networks need to be changed to not public. I HIGHLY recommend not being connected to untrusted networks when setting this up.
$nlm = [Activator]::CreateInstance([Type]::GetTypeFromCLSID([Guid]"{DCB00C01-570F-4A9B-8D69-199FDBA5723B}"));
  $connections = $nlm.getnetworkconnections();
  $connections | % {
      Write-Host "Connection " $_.getnetwork().getcategory();
      if ($_.getnetwork().getcategory() -eq 0)
      {
          Write-Host "Setting connection to private.";
          $_.getnetwork().setcategory(1);
      }
  }
It is time to setup the local computer which will be sending the commands to the remote computer. A security decision must be made as to which computers the local computer needs access to. Pass the computer(s) in the arguments.
param (
  $machines = $(throw "machines is required.")  # i.e. "*.domain.com" OR "name1.domain.com, name2.domain.com" sans quotes
)
Enable-PSRemoting -force
Enable-WSManCredSSP –role Client –DelegateComputer $machines -force
Now that the environments are setup, the following can be used to connect to the remote server.
Enter-PSSession -ComputerName name.domain.com
#Run your commands
If you need to specify which user to connect as or use CredSSP, you can use the following (this is needed when you want to get into SharePoint 2010):
Enter-PSSession -ComputerName name.domain.com -Authentication CredSSP -Credential $([Security.Principal.WindowsIdentity]::GetCurrent().Name)
#Run your commands
Finally, to clean up. To exit out of the session:
Exit-PSSession
In a future blog post I will cover using New-SPSession.

I adapted some of the Windows Remote Management (WinRM) parts of Zach Rosenfield's Remote Install of SharePoint (with SPModule) post for the purposes of this post. I probably could have found it in a million different places, but that was the site I found the information on.