olly - Fotolia
Mind the feature gaps in the PowerShell open source project
Administrators who switch to the cross-platform version of PowerShell might find it challenging to use, but there are several ways to cope with a transition from Windows PowerShell.
Even though the current version of the PowerShell open source project lacks much of the functionality of Windows PowerShell, administrators can close those gaps with a few adjustments.
Microsoft released the first version of its cross-platform, open source version of PowerShell in January 2018. This version, officially called PowerShell Core 6.0, is not a straight swap for Windows PowerShell 5.1, even though it's forked from the 5.1 code base and adapted for use on Windows, many Linux distributions and macOS.
The key difference is Windows PowerShell 5.1 and earlier versions run on the full .NET Framework for Windows, whereas the PowerShell open source project relies on .NET Core, which does not have access to the same .NET classes.
Differences between Windows PowerShell and PowerShell Core
Many PowerShell 5.1 features aren't available in PowerShell Core 6, including the Integrated Scripting Environment (ISE), PowerShell workflows, Windows Management Instrumentation (WMI) cmdlets, event log cmdlets, performance counter cmdlets and the Pester module.
The large collection of PowerShell modules that work with Windows PowerShell are not available in PowerShell Core 6. Any binary PowerShell module compiled against the full .NET Framework won't work in the PowerShell open source project, including the Active Directory module and the Exchange module.
PowerShell Core 6 brings some useful features. The first is the ability to administer Linux and macOS systems using PowerShell. The depth of cmdlets for Windows systems is not available on the non-Windows platforms, but the PowerShell community might fill those holes through the PowerShell Gallery.
Secondly, PowerShell 6 introduced remoting over Secure Socket Shell (SSH) as opposed to remoting with the Web Services-Management protocol. This enables remoting to and from Linux systems and provides an easy way to remote to and from non-domain Windows machines.
Installing and configuring SSH on Windows is getting easier, and the inclusion of SSH as an optional feature in the latest Windows 10 and Windows Server previews will hopefully lead to a simpler remoting installation and configuration process.
How to surmount functionality obstacles
You can overcome some of the missing features in PowerShell Core 6, starting with the ISE. Use Visual Studio (VS) Code instead of ISE for developing scripts. VS Code is an open source editor that runs on Windows, Linux and macOS. VS Code uses Windows PowerShell or PowerShell Core in the integrated terminal if both are installed.
PowerShell workflows, which allow functions to run on several machines at the same time, are never going to be a part of PowerShell Core because this feature is difficult to implement. Instead, you can use PowerShell runspaces to provide parallel processing. While they aren't easy to code, a proposal exists to create cmdlets for managing runspaces.
An example of a simple PowerShell workflow is:
workflow test1 {
parallel {
Get-CimInstance -ClassName Win32_OperatingSystem
Get-CimInstance -ClassName Win32_ComputerSystem
}
}
test1
Figure 1 shows the results of this script.
Emulating a PowerShell workflow with runspaces results in the following code:
## create runspace pool with min =1 and max = 5 runspaces
$rp = [runspacefactory]::CreateRunspacePool(1,5)
## create powershell and link to runspace pool
$ps = [powershell]::Create()
$ps.RunspacePool = $rp
$rp.Open()
$cmds = New-Object -TypeName System.Collections.ArrayList
1..2 | ForEach-Object {
$psa = [powershell]::Create()
$psa.RunspacePool = $rp
if ($_ -eq 1) {
[void]$psa.AddScript({
Get-CimInstance -ClassName Win32_OperatingSystem
})
} else {
[void]$psa.AddScript({
Get-CimInstance -ClassName Win32_ComputerSystem
})
}
$handle = $psa.BeginInvoke()
$temp = '' | Select-Object PowerShell, Handle
$temp.PowerShell = $psa
$temp.Handle = $handle
[void]$cmds.Add($temp)
}
## view progress
$cmds | Select-Object -ExpandProperty handle
## retrieve data
$cmds | ForEach-Object {$_.PowerShell.EndInvoke($_.Handle)}
## clean up
$cmds | ForEach-Object {$_.PowerShell.Dispose()}
$rp.Close()
$rp.Dispose()
Figure 2 shows this code running on PowerShell Core 6 in the VS Code editor.
Runspaces code works in Windows PowerShell 5.1 and PowerShell Core 6. Administrators can also simplify runspaces with the PoshRSjob module from the PowerShell Gallery. The latest version works in PowerShell Core 6 on Linux and Windows.
The developers of the PowerShell open source project plan to add missing WMI, event log and performance cmdlets into the Windows Compatibility Pack for .NET Core. WMI cmdlets are effectively deprecated in favor of the Common Information Model (CIM) cmdlets, which are available in PowerShell Core 6 and Windows PowerShell 3 and newer.
Event log cmdlets only work with the traditional event logs. If you need to work with the new style application and service logs, you have to use the Get-WinEvent cmdlet, which also works with the old-style logs.
The following command uses the older Get-EventLog cmdlet:
Get-EventLog -LogName System -Newest 5
It's easy enough to switch to the Get-WinEvent cmdlet to get similar results:
Get-WinEvent -LogName System -MaxEvents 5
The Get-WinEvent cmdlet can't clear, limit, write to or create/remove classic event logs, but you can configure event logs using the properties and methods on the objects returned.
Get-WinEvent -ListLog *
In Windows PowerShell 5.1, you can run the following command to access performance counters:
Get-Counter -Counter '\Processor(*)\% Processor Time'
This generates the following output:
Timestamp CounterSamples
--------- --------------
31/03/2018 15:18:34 \\w510w10\processor(0)\% processor time :
1.56703775955929
\\w510w10\processor(1)\% processor time :
0.00460978748879626
\\w510w10\processor(2)\% processor time :
1.56703775955929
\\w510w10\processor(3)\% processor time :
0.00460978748879626
\\w510w10\processor(4)\% processor time :
0.00460978748879626
\\w510w10\processor(5)\% processor time :
4.69189370370026
\\w510w10\processor(6)\% processor time :
3.12946573162978
\\w510w10\processor(7)\% processor time :
0.00460978748879626
\\w510w10\processor(_total)\% processor time :
1.37173676293523
The alternative way to return performance counter data is with CIM classes, which work in Windows PowerShell 5.1 and PowerShell Core 6:
Get-CimInstance -ClassName Win32_PerfFormattedData_PerfOS_Processor | select Name, PercentProcessorTime
Name PercentProcessorTime
---- --------------------
_Total 13
0 50
1 0
2 0
3 43
4 6
5 6
6 0
7 0
PowerShell Core 6 can access many of the older PowerShell modules, such as the networking or storage modules, available on Windows 8 or Windows Server 2012. To do this, add the following entry in your profile to the Windows PowerShell 5.1 modules folder:
$env:PSModulePath = $env:PSModulePath + ;C:\Windows\System32\WindowsPowerShell\v1.0\Modules\'
Another way to do this is to import the module directly.
Import-Module C:\Windows\System32\WindowsPowerShell\v1.0\Modules\NetAdapter\NetAdapter.psd1
Get-NetAdapter
Name ifIndex Status MacAddress LinkSpeed
---- ------- ------ ---------- ---------
vEthernet (nat) 16 Up 00-15-5D-82-CF-92 10 Gbps
vEthernet (DockerNAT) 20 Up 00-15-5D-36-C9-37 10 Gbps
vEthernet (Default Swi... 9 Up 2E-15-00-2B-41-72 10 Gbps
vEthernet (Wireless) 22 Up F0-7B-CB-A4-30-9C 144.5 Mbps
vEthernet (LAN) 12 Up 00-15-5D-36-C9-11 10 Gbps
Network Bridge 24 Up F0-7B-CB-A4-30-9C 144.5 Mbps
LAN 14 Disconnected F0-DE-F1-00-3F-67 0 bps
Wireless 8 Up F0-7B-CB-A4-30-9C 144.5 Mbps
In the case of binary modules, such as Active Directory, you'll have to revert to scripting when using the PowerShell open source version. If you want to administer Linux machines using PowerShell Core 6, you'll have to do a lot of scripting or wait for the community to create the functionality.