Every IT professional is interested in managing their servers remotely. It would be better if we can achieve our tasks on remote machines from our desk than having to travel to a data center (unless there's a physical failure).
Remoting is the key feature of Windows PowerShell. However, most security administrators consider this to be a security risk. This is not completely true; Windows PowerShell remoting works based on a two-way authentication (a mutual authentication), and this inherits the feature of the Active Directory Kerberos protocol. This applies only for domain-joined machines.
We will cover the following topics:
The Windows PowerShell remoting feature makes it richer, and this works based on the WS-Management protocol and the Windows Remote Management (WinRM) service. From Windows PowerShell 3.0 onward, the WS-Management configurations can be manipulated using the PowerShell provider, which is the WSMan drive.
WS-Management is a SOAP-based protocol for servers and is according to the DMTF open-based standard. Following are the standard abilities of DMTF Web Services Management (WSMan):
The WinRM service processes the request sent by WSMan over the network and the listening happens through the HTTP.sys
driver.
WSMan cmdlets are used to manage WSMan protocols. These commands are organized in the Microsoft.WSMan.Management
module. Run the following command:
Get-Command -Module Microsoft.WSMan.Management
The output is as shown in the following image:
In this exercise, let's take a look at how we can change the maximum session configurations. Let's consider the current maximum allowed connections.
Using the native PowerShell Get-Item
command, execute the following code and refer to the following image:
CD WSMAN:WMF5Node03ShellMaxShellsPerUser
Let us see the result of the following code:
Set-Item WSMan:wmf5node03ShellMaxShellsPerUser -Value 30
Using the WSMan cmdlets, we can manage the session's timeout period. Run the following command:
$Time = New-WSManSessionOption -operationtimeout 3000 Connect-WSMan -computer WMF5Node02 -sessionoption $Time
We can call Disconnect-WSMan
to disconnect the client from the WinRM service. Once this is executed, we don't see the remote computer in the WSMan drive.
Now, let's establish a connection with the remote LYNC 2013 server using the WSManConnectionInfo
class using C# and PowerShell. Following is a sample code:
using System; using System.Collections.Generic; using System.Linq; using System.Management.Automation; using System.Management.Automation.Remoting; using System.Management.Automation.Runspaces; using System.Security; using System.Collections.ObjectModel; using System.Text; namespace Office365 { class Program { static void Main(string[] args) { string username = "DSCDEMOLAB\SKBAdminID"; string password = "SecureString"; System.Security.SecureString securepassword = new System.Security.SecureString(); foreach (char c in password) { securepassword.AppendChar(c); } PSCredential credential = new PSCredential(username, securepassword); WSManConnectionInfo connectioninfo = new WSManConnectionInfo(new Uri("https://RemoteServer/OcsPowershell"), "http://schemas.microsoft.com/powershell/Microsoft.PowerShell", credential); connectioninfo.AuthenticationMechanism = AuthenticationMechanism.Default; connectioninfo.SkipCACheck = true; connectioninfo.SkipCNCheck = true; //connectioninfo.AuthenticationMechanism = AuthenticationMechanism.Basic; connectioninfo.MaximumConnectionRedirectionCount = 2; //connectioninfo.MaximumConnectionRedirectionCount = 2; using (Runspace runspace = RunspaceFactory.CreateRunspace(connectioninfo)) { runspace.Open(); using (PowerShell powershell = PowerShell.Create()) { powershell.Runspace = runspace; //Create the command and add a parameter powershell.AddCommand("Get-CsUser"); Collection<PSObject> results = powershell.Invoke(); foreach (PSObject result in results) { Console.WriteLine(result.Properties["SamaccountName"].Value.ToString()); Console.ReadLine(); } } } } } }
Refer to the following image:
We used the WSManConnectionInfo
class, which provides us with the connection information that is needed to connect to a remote runspace. Windows PowerShell uses a WinRM connection to connect to the computer on which the remote runspace is opened. Execute the following code:
WSManConnectionInfo connectioninfo = new WSManConnectionInfo(new Uri("https://RemoteServer/OcsPowershell"), "http://schemas.microsoft.com/powershell/Microsoft.PowerShell", credential); "https://RemoteServer/OcsPowershell"
This is our remote Skype for Business server URL using which we can explore Skype for Business Web Front End Server (IIS). Using the preceding code, we can establish the connection and query information from the remote servers.
The same can be achieved using PowerShell. Execute the following code:
$cred = Get-Credential "DomainSKBAdmin" $session = New-PSSession -ConnectionURI "https://RemoteServer/OcsPowershell" -Credential $cred Import-PsSession $session Error: Access denied due to incorrect credentials (401 status code)
The output of the code we just saw is shown in the following image:
For learning purpose, we can get the certificate information and add it to Current User | Trusted Root Certification Authorities and execute the PowerShell code—Yes! Connection establishes as expected.
To get the certificate information, you can go to the site, https://RemoteServer/OCSPowerShell. Take a look at the following image:
Click on the Lock button in your browser and get the information.
To configure the HTTP or HTTPS Listener, we need to ensure that the ports, 5985 and 5986, are opened. The transport happens through the respective ports. Using PowerShell, we can easily enable the HTTP listener. Run the following command:
Set-WSManQuickConfig
To avoid the access denied error, ensure that PowerShell is running as Administrator. This is applicable for Win 7 and 2008 server OS. The command works without elevated privileges if you run it under the local admin account. Take a look at the following image:
The output is as follows:
PS C:Windowssystem32> Winrm Enumerate Winrm/config/Listener Listener Address = * Transport = HTTP Port = 5985 Hostname Enabled = true URLPrefix = wsman CertificateThumbprint ListeningOn = <IPS>
By default, the HTTP listener will be created to enable HTTPS; we need to use the switch, –UseSSL
.
Let's give it a try with the following command:
Set-WSManQuickConfig -UseSSL
The error is self-explanatory. This is the really cool stuff in Windows PowerShell. Take a look at the following image:
To overcome this, we can use the following code. You can check with your certification authority (CA) administrator for the certificate-related query:
$Cert = Get-ChildItem Cert:LocalMachineMy | where {$_.Subject -match $env:COMPUTERNAME} "The installed SSL certificate: " + $Cert.Subject $CertPrivKey = $Cert.PrivateKey $KeyCertFile = Get-Item -path "$ENV:ProgramDataMicrosoftCryptoRSAMachineKeys*" | where {$_.Name -eq $CertPrivKey.CspKeyContainerInfo.UniqueKeyContainerName} $KeyAcl = (Get-Item -Path $KeyCertFile.FullName).GetAccessControl("Access") $perm = "NT AUTHORITYNETWORK SERVICE","Read","Allow" $accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule $perm $KeyAcl.AddAccessRule($accessRule) Set-Acl $KeyCertFile.FullName $KeyAcl
Now, the following code will work:
Set-WSManQuickConfig -UseSSL
The output is as shown in the following code:
Listener Address = * Transport = HTTPS Port = 5986 Hostname Enabled = true URLPrefix = wsman CertificateThumbprint = D3438E6116227BA1459434943DB723C2C5D50C7C ListeningOn = <IPS>
In case this is a workgroup, we can add trusted hosts to accept the connections. This way, we can have more control in remoting. Your client accepts the connection only if it's listed in the trusted hosts.
We have covered a few basic examples of CIM and WMI in Chapter 2, Unleashing Development Skills Using Windows PowerShell 5.0; let's take a quick review here and proceed with a few more examples using PowerShell and C#.
You may wonder, why do we need CIM, and why not WMI? In this topic, we'll discover how CIM helps IT professionals.
CIM provides a rich experience in PowerShell and supports standard compliance—yes; CIM does work in Windows- and nonWindows-based machines.
CIM is introduced in Windows PowerShell 3.0 with the 2012 server by default, but this is limited; it supports down-level OS as well.
To know all the available CIM cmdlets, use the following code:
Get-Command -Module CimCmdlets | Select Name
Following is a list of available CIM cmdlets:
Take a look at the following image:
CIM cmdlets have auto tab completion, so it involves little typing and coding. Do remember that the default namespace is root/cimv2
.
Now, let's take a look at the list of CIM classes:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Management.Automation; using System.Management.Automation.Host; using System.Collections.ObjectModel; namespace CIM_Exercise { class Program { static void Main(string[] args) { using (PowerShell PowerShellInstance = PowerShell.Create()) { PowerShellInstance.AddCommand("Get-CimClass"); Collection<PSObject> result = PowerShellInstance.Invoke(); foreach (PSObject r in result) { Console.WriteLine(r); Console.ReadKey(); } } } } }
Ensure that you call a property that exists. If we don't use an existing property, the following error will appear:
After a successful execution, we will obtain the list as shown in the following image:
Using the Invoke-CimMethod
cmdlet, we can perform operations such as creating, terminating, restarting, and so on.
In this exercise, let's consider the basic example of opening a notepad. Yes! We can simply type the word notepad
in PowerShell, and this will do it. But we will explore the CIM methods using the Invoke-CimMethod
cmdlet and its parameters.
The following is a single line of code in PowerShell that uses the Invoke-CimMethod
cmdlet:
Invoke-CimMethod -ClassName Win32_Process -MethodName "Create" -Arguments @{Commandline = "notepad.exe"}
The following is a single line of code in PowerShell that uses the [WMICLASS]
type accelerator:
([wmiclass]"rootcimv2:Win32_Process").Create('notepad.exe');
So, how do we find out the parameters of the methods? Run the following command and refer to the following image:
(Get-CimClass -ClassName Win32_Process).CimClassMethods
For each method name, we can see the parameters. It's easy to explore and use as required.
Now, let's create a small Windows form application and take note of the execution of CIM methods.
Following is the code used for this:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Management.Automation; using System.Management.Automation.Runspaces; namespace CIM_Exercise { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { using(PowerShell PowerShellInstance = PowerShell.Create()) { PowerShellInstance.AddScript("Invoke-CimMethod -ClassName Win32_Process -MethodName Create -Arguments @{CommandLine = notepad.exe}"); PowerShellInstance.Invoke(); } } private void button2_Click(object sender, EventArgs e) { using (PowerShell PowerShellInstance = PowerShell.Create()) { PowerShellInstance.AddScript("Invoke-CimMethod -ClassName Win32_Process -MethodName Create -Arguments @{CommandLine = calc.exe}"); PowerShellInstance.Invoke(); } } } }
To avoid overuse of Add
parameters in the PowerShell instance, we used the type accelerator method. The Windows form provides the options of Open Notepad, which opens the Notepad application, and Open Calc, which opens the Calculator application, as shown in the following screenshot:
As we have previously seen, CIM supports down-level OS. You may wonder, can we not use CIM commands in servers running Windows 2008 with PowerShell 2.0? Not really, but we can establish a remote session and execute the CIM commands.
Consider a scenario where we need to query the OS-installed date on remote machines. WMI will do it, but we need to add a snippet of code for creating the time format, which is as follows:
(Get-WmiObject -Class Win32_operatingSystem –ComputerName "Remote").InstallDate #20140326181309.000000+060 (Get-CimInstance -ClassName CIM_OperatingSystem –ComputerName "Remote").InstallDate #Wednesday, March 26, 2014 6:13:09 PM
Which one of these would our configuration management team prefer? Of course, they would prefer the one with the well-formatted date. Indeed, we can do this in WMI as well by adding a snippet of code as follows:
$os = (Get-WmiObject -Class Win32_operatingSystem) [management.managementDateTimeConverter]::ToDateTime($os.InstallDate)
There are always multiple ways of doing things in PowerShell, and we can choose the one that best suits our requirement.
In this exercise, let's consider using the server remotely with PowerShell 2.0, and execute the CIM commands:
Test-WSMan -ComputerName RemoteServer wsmid : http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd ProtocolVersion : http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd ProductVendor : Microsoft Corporation ProductVersion : OS: 0.0.0 SP: 0.0 Stack: 2.0
OS: 0.0.0 SP: 0.0 Stack: 2.0
proves that the remote machine is PowerShell 2.0.
So now, let's establish a session using the following code and get the OS-installed date:
$Dcom = New-CimSessionOption -Protocol Dcom $session = New-CimSession -ComputerName RemoteServer -SessionOption $Dcom (Get-CimInstance -CimSession $session -ClassName Win32_OperatingSystem).InstallDate
In this chapter, we explored the basics of Windows Remote Management; in the next chapter, we will discuss how to create DSC with MOF using class, deploying configuration, and the types of deployment modes.