Sunday, March 29, 2015

PowerShell : A deep dive into remoting - Part 8

Before you start using Windows PowerShell on an Azure VM, you first need to ensure that Azure PowerShell module is installed on the VM. Azure PowerShell module is the one which provided all the cmdlets to manage the Azure VM infrastructure using PowerShell. You can download and install the Azure PowerShell modules by running the Microsoft Web Platform Installer on the VM. When prompted, click Run and the Web Platform Installer will install the Azure PowerShell modules and all dependencies or you can visit the link at http://azure.microsoft.com/en-us/downloads/#cmd-line-tools and install the Azure command-line interface. 

After the installation is complete, you can verify whether the Azure module is available by using the Get-Module -ListAvailable command.

Before you start working with the cmdlets, you need to authenticate to Windows Azure, you can either use the username and password method or use a certificate to connect to the subscription.
The Windows Azure PowerShell module includes cmdlets that help you download and import the certificate. First you have to use the Get-AzurePublishSettingsFile cmdlet which will open the Azure Management portal for you to download the subscription settings file. After downloading and saving the file to a location on the hard drive, you can use the Import-AzurePublishSettingsFile cmdlet to import the .publishsettings file for use by the module. This file includes a management certificate that has security credentials.

Once you have the subscription settings configured properly, you can now use the remote commands as in any server.  Remoting on Azure machine uses SSL and the port 5986 by default. You can test this by trying to create a PowerShell session like
Enter-PSSession azurevm1.cloudapp.net –Port 5986 –UseSSL –Credential (Get-Credential)

If the certificate from the remote machine is not added to the trusted authority of the local computer, then you’ll get an error saying “The server certificate on the destination computer (.cloudapp.net:) has the following errors: The SSL certificate is signed by an unknown certificate authority.”. If the certificate error is thrown then you need to add the certificate from the remote server to the trusted authority.

If the common name of the certificate does not match the hostname (server you are initiating the remote execution), you may need to use the SkipCACheck and SkipCNCheck options while remoting.

Enter-PSSession -ComputerName azurevm1.cloudapp.net -Credential (Get-Credential) -Port 5986 -UseSSL -SessionOption (New-PSSessionOption -SkipCACheck -SkipCNCheck)

PowerShell : A deep dive into remoting - part 7

In remoting when a user logged into a computer uses a command to execute a script block or another command on the remote machine that needs to access another machine remotely (a very common scenario is a SharePoint farm) where Kerberos is not enabled, you may encounter a problem called 'Double hop'. Double hop refers to the problem where the first server accessed via remoting tries to access the second server by default using the credentials the PowerShell process is running under. The problem arises because the credentials that the remote server uses to access the second server may not have the required permissions to perform the action.

The problem is related to the way Windows PowerShell delegates the credentials from Server1 to Server2. During delegation, any script or command executed on Server2 will be executed as the user that is defined by the credential. By default delegation can only traverse one hop, that means Server2 does not have the permission to delegate the credential to Server3 and it uses the credential of the PowerShell process to execute the script/ command on Server3 resulting in the problem. 

To get around this issue you need to use the CredSSP authentication mechanism in PowerShell.
Credential Security Service Provider (CredSSP) is a new security service provider that is available through the Security Support Provider Interface (SSPI) in Windows. CredSSP enables an application to delegate the user’s credentials from the client (by using the client-side SSP) to the target server (through the server-side SSP). With CredSSP enabled, the process that invokes a command remotely on Server1 passes the credential explicitly to Server2 during the first hop, and when Server2 needs to access Server3 for further activities during the same command execution, it uses the same credentials that was received from Server2 and so on.

Before enabling or activating CredSSP, it’s important that you understand the two type of roles involved in this process (Client and Server).
In CredSSP, the team Client is referred to the machines that starts the process of remote execution by passing the credentials. Servers are the machines that are accessed remotely.
In order to make a machine in your domain, allow incoming CredSSP connections, then you need to configure that machine with the role CredSSP server. 

The server role can be assigned by executing the command
Enable-WSManCredSSP -Role Server -Force.

To setup a machine to delegate credentials to the remote computer so every remote access from the remote machine will also work, you have to enable the Client role on that machine. The client role can be assigned by executing the command  
Enable-WSManCredSSP Client –DelegateComputer '*.mydomain.com' -Force

For e.g. if you have a build server in your domain that needs to execute a script block on an application server in your SharePoint farm, then you have to configure the Build server with the role client and the servers in the SharePoint farm with role both server and client (this is to make sure that these servers can pass and accept credentials during a second hop).


Under the hood, enabling WsManCredSSP will alter the WS-Management setting WSMAN:\localhost\Client\Auth\CredSSP to true on the client machine and WSMAN:\localhost\Service\Auth\CredSSP to true on the server machine. It will also take care of setting the local policy 'Allow delegating fresh Credentials' on the servers that are configured with Client role.


Wednesday, March 25, 2015

PSTip : Open file and open folder dialog

Did you had issues whenever the users were expected to provide the full path for the file or folder to work on with a script?
Well, instead of asking them to type the path, you can use the Winforms API to choose the file/ folder. I have create couple of methods to add into my PS modules for using in this scenario.

Function Open-File
{
      param
      (
            [String] $Title = "Choose the file",
            [String] $Filter = "*.*",
            [String] $InitialDirectory = "C:\"
      )

      [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
      $dialog = New-Object System.Windows.Forms.OpenFileDialog
      $dialog.Title = $Title
      $dialog.Filter= $Filter
      $dialog.InitialDirectory = $InitialDirectory
      $result = $dialog.ShowDialog()
      if($result -eq [System.Windows.Forms.DialogResult]::OK)
      {
            $dialog.FileName
      }
      else
      {
            [String]::Empty
      }
}

Function Open-Folder
{
      [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
      $dialog = New-Object System.Windows.Forms.FolderBrowserDialog
      $dialog.RootFolder = "Desktop"
      $dialog.ShowNewFolderButton = $true
      $result = $dialog.ShowDialog()

      if($result -eq [System.Windows.Forms.DialogResult]::OK)
      {
            $dialog.SelectedPath
      }
      else
      {
            [String]::Empty
      }

}

Monday, March 23, 2015

PowerShell : A deep dive into remoting - Part 6

Implicit remoting is a powerful feature of PowerShell remoting that enables you to import remote commands into your local session, or store the imported commands on the local disk for later use and use them as if they  are available on the local computer. With implicit remoting it’s possible to use the commands available in a PowerShell module added to a remote computer to execute on the local machine. Even though the commands are invoked from the local machine and looks like they are executed locally, in reality they are shortcuts/ proxies to the actual commands and will execute on the remote machines. After execution the results are transferred to the local computer via remoting.
To understand the details of implicit remoting and how it works, let’s look into the sample scenario given below.


What I’ve done here is imported a module (PSSQL) using a session that was created before and then imported that session to the local computer with the module PSSQL so that I can use the commands that are available as part of that module on my computer. To easily identify the commands that are imported as part of the Import-PSSession I’ve prefixed the commands REMSQL.

Now I can execute the cmdlets that are listed by the Get-Command –Noun REMSQL* command in the screenshot as if I execute any local commands. Please note that the behavior of the execution is the same as for other commands that are executed remotely. The objects that are returned as part of the execution will not have any methods attached to them as they are actually serialized objects from the remote machine. If you have imported a module from a computer, you need to remember that the commands run on the remote computer. If you run Get commands, they will get data from the remote computer. If you run Set commands, they change data on the remote computer. The commands look and feel local, but they're remote commands.
Persisting the imported commands

The commands that you have imported using Import-PSSession option will only stay in the local computer till the session is active. That means as soon as the remote session is closed or exited, you'll lose the commands. If you still want to keep the imported commands for later use even after the session is closed, then you need to persist the commands on the local machine.
The Export-PSSession cmdlet will help you persist the imported commands from another session and saves them in a Windows PowerShell module.

Unlike Import-PSSession, which imports commands from another PSSession into the current session, Export-PSSession saves the commands in a module. The commands are not imported into the current session. By default, Export-PSSession exports all commands, except for commands that exist in the current session, but you can use the CommandName parameters to specify the commands to export.
The Export-PSSession cmdlet uses the implicit remoting feature of Windows PowerShell. When you import commands into the current session, they run implicitly in the original session or in a similar session on the originating computer.

For e.g the above command will export the commands available in the module SQLPS to a module REMSQLPS on the local machine and can be used later for execution. Export-PSSession command support multiple arguments that can be used to customize the export, like –CommandName, -CommandType etc. Once you have exported the commands and persisted on the local computer, you can later use the Import-Command to load these modules whenever needed and work on the commands like any other powershell commands. While executing these commands, PowerShell will take care of creating a new remote session and managing it.

PowerShell : A deep dive into remoting - Part 5


PowerShell sessions are the core components of PowerShell remoting. So let’s spend some more time understanding the details of PowerShell sessions and the configurations. Every time we execute the Invoke-Command with the -ComputerName argument, a temporary session is created to execute the remote command and then released after the command is executed. A PowerShell session or PSSession represents a connection between the computer that invokes a remote command and the remote computer. A good practice to follow when you are planning to connect to a remote computer several times and executing commands is to create a PSSession and reuse this session for the work. This way, you can manage a single connection to a PowerShell host instance and have a persisted session in use.
When using a persistent connection, the commands that are executed against the session will remain in effect till the session is removed. For e.g. You can add snapins and load modules at the beginning and then use the cmdlets or functions from these snapins/ modules later in the session.

Creating and using sessions
To create a persistent session, you can use the New-PSSession command as given below
$session = New-PSSession -ComputerName COMP1

The command creates a session object and assigns it the the $session variable. The New-PSSession command also allows -Credential parameter to use to connect to the remote computer as a specific user.
$session = New-PSSession -ComputerName COMP1 -Credential (Get-Credential)

By default PowerShell uses the port 5985 for HTTP and 5986 for HTTPS connections. If the remote computer has the WinRM configured on a different port, you can mention that Port using the -Port argument for the New-PSSession command.
Every time a session is created PowerShell automatically uses the default session configuration unless you specify a different session configuration or have secured session configurations. If you want to override this behavior then you need to create a Session configuration and use the –ConfigurationName argument to use this configuration for the session.

After the session is created you can initiate a one-one connection to the remote computer using an Enter-PSSession cmdlet by using the –Session argument
Enter-PSSession –Session $session

The session object that is created will remain open till it is closed explicitly. You can use the Get-PSSession cmdlet to check the currently available sessions that is created.
Get-PSSession | fl *

Disconnect and connect to sessions
If you want to execute a long running process like configuring a SharePoint farm on a remote computer by using a remote session and you don't want to connect to the session from the current computer, but later connect from a different machine, you can use the Disconnet-PSSession and Connect-PSSession cmdlets.

The Disconnect-PSSession cmdlet disconnects a PSSession, from the current session. As a result, the PSSession is in a disconnected state. You can connect to the disconnected PSSession from the current session or from another session on the local computer or a different computer. Note that Disconnect-PSSession cmdlet disconnects only open PSSessions that are connected to the current session. Disconnect-PSSession cannot disconnect broken or closed PSSessions, or interactive PSSessions started by using the Enter-PSSession cmdlet, and it cannot disconnect PSSessions that are connected to other sessions.
You have to explicitly perform the action of disconnecting the session. A good practice is to start a session from one computer, disconnect it, and then reconnect to that session from another computer.

Get-PSSession -Session $session | Disconnect-PSSession
Once you have disconnected the session from the current host, you can later use the Connect-PSSession to reconnect the session from another computer by specifying the ComputerName that the session is available.

Connect-PSSession -ComputerName COMP1
Using the session options
There are a number of other cmdlets for the advanced configuration of remote PowerShell sessions. The first and most obvious of these is the New-PSSessionOption cmdlet, which enables an administrator to configure advanced options for use with the New-PSSession cmdlet. For instance, if you want to change the default culture to nl-nl and set the maximum object size that can be recived to 10 MB, you can use the

$nlSession = New-PSSessionOption -Culture "nl-nl" -MaximumReceivedObjectSize 10MB
To persist a session option created to use later, you can export the object to xml using the Export-CliXml cmdlet and then later import the object when creating a new session.

$nlSession | Export-CliXml c:\PSSessions\nlSession.xml
New-PSSession -ComputerName COMP1 -SessionOption (IMport-CliXml c:\PSSessions\nlSession.xml)

Thursday, March 5, 2015

PowerShell : A deep dive into remoting - part 4


There are two common options for approaching remoting with PowerShell. The first is known as one-to-one remoting, in which you
essentially bring up an interactive PowerShell prompt on a remote computer, where you can enter the commands that are executed on the remote computer. The second option is called one-to-many remoting and it is especially suited for situations when you may want to run the same commands or scripts in parallel to several remote computers.

To start a one-to-one remoting session, you can use the Enter-PSSession cmdlet by specifying the computer name as
Enter-PSSession -ComputerName "COMP1"

The cmdlet also supports the -Credential parameter to enter the remote session with the credentials supplied.

After entering the session, you can see that the powershell prompt now contains the computer name and you can execute cmdlets on the remote computer

Once you are in a remote session, the commands executed are transported to the remote computer and the result of execution is returned back as serialized XML format back to the machine which is deserialized into objects back and passed to the pipeline.

Mind that any Snapins added to the local session will not be available on the remote session, you need to add the snapins on the remote session after entering the session, the same applies to the imported modules.
When you’ve finished with the remote machine, run Exit-PSSession. This will return you to your local prompt, close the connection to the remote machine, and free up resources on the remote machine. This will also happen automatically if you just close the PowerShell window.

The Get-PSSession cmdlet will show any active sessions currently available.
If you want to execute cmdlets on multiple computers,then you have to use the One-to-many remoting technique using the Invoke-Command cmdlet. This will transmit the commands to multiple remote computers and executed there. The results are again serialized into XML and send back to the executing machine which is deserialized into objects to be put back to the pipeline.

The Invoke-Command has a -ScriptBlock parameter that is used to specify a scriptblock to be executed on the remote computer as

Invoke-Command -ScriptBlock {Get-EventLog -LogName Application -EntryType Error -Newest 10} -ComputerName COMP1

This will invoke the Get-EventLog cmdlet and then serialize the results to XML and return back to the executing machine, where the data is deserialized back to the System.Diagnostics.EventLogEntryType. The computername parameter ensures that the script is executed on COMP1 with the credentials of the current user.
The Invoke-Command also accepts multiple computer names like 
Invoke-Command -ScriptBlock {Get-EventLog -LogName Application -EntryType Error -Newest 10} -ComputerName "COMP1, COMP2, COMP3"

You can also pass a credential object to the Invoke-Command to execute the command as a different user
Invoke-Command -ScriptBlock {Get-EventLog -LogName Application -EntryType Error -Newest 10} -ComputerName "COMP1, COMP2, COMP3" -Credential (Get-Credential -Username "domain\username" -Message "Enter password")

If you want to pass arguments to the Invoke-Command then you have to use the ArgumentList parameter as in the e.g. below
Invoke-Command -ScriptBlock { param($name} Get-EventLog -Application $name -Newest 5} -ComputerName COMP1 -ArgumentList "Application"

The ArgumentList accepts an array of objects, so if you have multiple arguments you need to pass it as an array as given below
$arguments = @"arg1", "arg2", arg3)
Invoke-Command -ScriptBlock ${function:Do-Something} -ArgumentList $arguments -ComputerName COMP1

If you want to run scripts on the remote machine, you need to use the -FilePath parameter

Invoke-Command -FilePath C:\Temp\Script1.ps1 -ComputerName COMP1
This will execute the script file in the local machines C:\Temp\Script1.ps1 location on the remote computer (COMP1). If you need to execute a script file that is present on the remote machine, then you have to use the filepath in the -ScriptBlock parameter as
Invoke-Command -ComputerName COMP1 -ScriptBlock {C:\Temp\Script1.ps1}

PowerShell : A deep dive into remoting - part 3


Windows PowerShell contains a PSProvider implementation for WSMan which exposes the WS-Management configuration settings with a directory structure. The settings are grouped as containers for each group of settings.
For e.g. to see the client settings on the machine.
use the Get-ChildItem wsman:\localhost\client cmdlet and you can find all the properties for the client


This information can be used to configure various aspects of the WS-Management client. The configuration information is stored in the registry. For e.g. from the above screenshot you can see that I have added all the computers to the trustedhosts. This is not a very good practice to follow in a real world scenario. It’s better that you can restrict access to only the computers that you trust to remote access the resources.
To change the value of the trusted hosts and only give access to specific computers, you can use the Set-Item cmdlet on the client settings as

Set-Item wsman:\localhost\client\TrustedHosts "COMP1, COMP2" -Force
This will add the COMP1 and COMP2 machines to the trusted hosts and only allow remote connections from those machines. If you want to trust all the computers in your domain, then you can also make use of the wild card implementation as

Set-Item wsman:\localhost\client\trustedhosts "*.yourdomain" -Force
You can also use the Connect-WSMan cmdlet to connect to the WinRM service on a remote computer. The Connect-WSMan cmdlet accepts the name of computer to connect. By default the logged in user credentials are used to connect to the machine. You can also use the -Credential parameter to specify a PSCredential object to impersonate. The  command also supports -Authentication parameter which is used to specify the AuthenticationMechanism. We'll look into the details of Authentication in the upcoming posts of this series.

After you connect to the WinRM service on the remote computer, the remote computer will appear in the root directory of the WSMan provider. You can now query the remote computer as any other PSProvider using the Get-Item, Get-ChildItem cmdlets and even make changes by using the Set-Item
For e.g. if you want to change the TrustedHosts settings for the remote machine COMP1, you can follow the steps given below

Connect-WSMan -ComputerName COMP1 -Credential (Get-Credential -Username "yourdomain\comp1user" -Message "Provide password for COMP1User")
Get-ChildItem wsman:\COMP1\Client

Set-Item wsman:\COMP1\Client\TrustedHosts "*.yourdomain" -Force

Wednesday, March 4, 2015

PowerShell : A deep dive into remoting - part 2


To get PowerShell remoting working, you need to have the WinRM service up and running and configure it for remoting. WinRm is Microsoft’s implementation of the industry standard WS-Management Protocol which is a DMTF open standard defining a SOAP-based protocol for the management of servers, devices, applications and various Web services. WinRM uses SOAP over HTTP and HTTPS, and thus is considered a firewall-friendly protocol. It was designed to provide interoperability and consistency for enterprise networks that have a variety of operating systems, to locate and exchange management information. WinRM is not exclusive to PowerShell, but when received a traffic that is tagged for PowerShell it can take care of accepting and passing the details to PowerShell.
WinRM is the “server” component of remote management application and WinRS (Windows Remote Shell) is the “client” for WinRM, which runs on the remote computer attempting to remotely manage the WinRM server. It’s important that the computer that needs to be remotly accessed and the computer that has to access the remote computers must have WinRM installed and enabled on them for WinRS to work and retrieve information from the remote system

To setup the computer for remote access, you need to first ensure that the WinRM service is started and running. To check that you can use the Get-Service cmdlet as given below
Get-Service –Name WinRm | select –expand Status

WinRM uses configuration items endpoint and listeners to receive traffic from a specific application. An application using WinRM should have an endpoint configured, it’s also fine if an application have multiple endpoints setup. Listeners are configuration items that the application uses to accept incokming traffic. You can see the listeners setup for WinRM by using the cmdlet
Get-WSManInstance winrm/config/Listener –Enumerate
the default ports used for WS-Management and PowerShell remoting are 5985 over HTTP an 5986 over HTTPS. You can add more listeners if you want using the New-WSManInstance cmdlet. The easiest way to setup PowerShell remoting is by using the Set-PSRemoting cmdlet. This will execute the following tasks on the machine

Enable-PSRemoting –Force –Confirm:$true
  • Checks whether the WinRM service is started. If stopped, it starts the service or it will restart the service
  • Sets the start mode of WinRM service to auto
  • Creates a WinRM listener for HTTP traffic on port 5985 for all local IP addresses.
  • Creates a Windows Firewall exception for the WinRM listener.
  • Setup endpoints for the applications Microsoft.PowerShell, Microsoft.PowerShell32, Microsoft.ServerManager,  Microsoft.Windows.ServerManagerWorkflows and Microsoft.PowerShell.Workflow
By default, Windows PowerShell Remoting uses Kerberos authentication, which requires a domain controller. If you are not using a domain or need to connect to machines outside your own trusted domain(s), you need to add all computers to the trustedhosts by using the Set-Item cmdlet.

Set-Item wsman:\localhost\client\trustedhosts * -Force
You can note that PowerShell has a PSProvider implementation fo WSMan and you can now query it as a file system.

Next in the series we’ll see how to execute cmdlets using a remote session.

PowerShell: A deep dive into remoting – part 1


One of the most important aspects of PowerShell is remoting. Introduced in PowerShell v2, remoting is a complex technology with a lot of confusion around it. I’ll try to go deep into the concepts of powershell remoting and technologies and see how it all works together with different protocols and implementations.
Classic cmdlets that have the –ComputerName parameter:

These commands use their own proprietary communications protocols, most often DCOM or RPC, and are generally limited to a single task. With this type of remoting, it is up to the cmdlet author to choose and implement the appropriate technology. You can find out these commands by using the Get-Command cmdlet and filtering them based on the parameter containing ComputerName as given below.

Get-Command  -CommandType  Cmdlet|? {$_.Parameters.Keys –contains “ComputerName”}

Lets try to see the behavior of couple of these cmdlets for eg. Get-Process and Get-Service. You can invoke both of these cmdlets on a remote computer by using the ComputerName parameter as
Get-Service –ComputerName “COMP1” | select name
Get-Process –ComputerName “COMP1” | select name

PowerShell will try to authenticate to the remote machine using the current user account. If the current user is also added into the Administrators group on the remote machine, you will not face any issues while executing these cmdlets.
Now lets see the behavior of these cmdlets when RemoteRegistry service is stopped on the remote machine.

For that you can use the Get-WmiObject cmdlet to access the service and stop it.
$remoteReg = Get-WmiObject –Class Win32_Service –ComputerName “COMP1” –Filter ‘name=”RemoteRegistry”’
$remoteReg.StopService()

Check the status code returned as part of the StopService method call.

For more details on the ReturnValue from the StopService method on a Win32_Service object refer to this table https://msdn.microsoft.com/en-us/library/aa393673(v=vs.85).aspx

Now if you try to execute the Get-Service cmdlet on the computer, you’ll see that it still works fine, but the Get-Process will throw an error!!!

As you have seen from the examples given, the technology used to implement remoting in these cmdlets vary and is not very transparent to the user. The error messages can also be very confusing when using these cmdlets. Try the Get-EventLog cmdlet and see the error message while remote registry service is stopped.

With PowerShell v2.0, remoting was introduced, which involves transferring the commands to the remote system making use of WinRM service and executing the command on the remote machine. This introduces our next type of cmdlets using remoting like the Invoke-Command and Enter-PSSession.
I’ll explain the details of these cmdlets and WinRM in the next post of the series.