I've been trying to increase my Linux skills, especially as I begin to write PowerShell scripts and tools that can work cross-platform. One very important concept I want to make sure you don't overlook is that even when scripting for non-Windows platforms, you must still be thinking about objects. The assumption is that you are writing PowerShell commands to co-exist and interoperate with other PowerShell commands. So even though Linux and MacOS are text-based, you need to work with objects.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
Linux Commands to Objects
As an example, consider this Linux command.
The command is writing strings to the pipeline, even though it looks like an object. Why not turn it into an object? I can split the output into an array of strings and then split each line into two parts using the : as a delimiter.
The hashtable, $h, becomes the pre-cursor to an object. By the way, I am removing the space so that the property name will have no spaces.
Let's jump right to the finished product.
A Cross-Platform Reference Function
#requires -version 6.2
#requires -psedition Core
<#
Convert this output:
Distributor ID: Ubuntu
Description: Ubuntu 18.04.3 LTS
Release: 18.04
into a PowerShell object
Requires LSB-Core package
# https://www.computerhope.com/unix/lsb_release.htm
#>
Function Get-LinuxLSB {
[cmdletbinding()]
[alias("lsb")]
[outputtype("LinuxLSB")]
Param(
[Parameter(Position = 0)]
[ValidateNotNullorEmpty()]
[string]$Hostname = [Environment]::Machinename,
[Parameter(Position = 1)]
[ValidateNotNullorEmpty()]
[string]$UserName
)
Write-Verbose "Starting $($myinvocation.MyCommand)"
#define a scriptblock to run locally or remotely
$sb = {
if ($isLinux) {
try {
$app = Get-Command -Name lsb_release -erroraction stop
$ok = $True
}
catch {
Write-Warning "This command relies on lsb_release. You may need to install the lsb-core package."
$ok = $false
}
if ($ok) {
$data = (lsb_release -idr) -split "`n"
$data | ForEach-Object -Begin { $h = [ordered]@{PSTypename = "LinuxLSB" } } -Process {
$s = $_.split(":")
Write-Verbose "Adding $s[0]"
$h.add($s[0].Replace(" ", ""), $s[1].trim())
} -end {
$h.Add("Computername", [environment]::MachineName)
New-Object -TypeName PSObject -Property $h
}
}
}
else {
Write-Warning "This command requires a Linux distribution"
}
} #close scriptblock
Write-Verbose "Querying $hostname"
if ($Hostname -eq [Environment]::Machinename) {
Invoke-Command -ScriptBlock $sb
}
else {
$params = $myinvocation.BoundParameters
$params.Add("SSHTransport", $True)
$params.Add("Scriptblock", $sb)
$params.Add("HideComputername", $True)
Invoke-Command @params | Select-Object -Property * -exclude RunspaceID
}
Write-Verbose "Ending $($myinvocation.MyCommand)"
}
This function leverages the remoting changes introduced in PowerShell Core that allow you to connect to a remote computer via SSH. This command uses SSH-based PowerShell remoting if the computer name (ie Hostname) is something other than the localhost. As a side note, normally I prefer to use $env:Computername to reflect the local computer name, but that isn't an option in PowerShell on Linux so I'm resorting to the .NET Framework.
Here's the command in action locally on an Ubuntu instance.
And here it is in action in PowerShell 7 on a Windows system:
Summary
I don't expect this function to be especially useful and hope you view it more as a proof of concept and showcase for some scripting techniques you might use when working cross-platform. You could do something similar to the output of the hostnamectl command.
But I'll leave that fun to you. In the meantime, give the function a spin. Maybe enhance it a bit. And I'd love to hear about your cross-platform scripting experiences.
and yet another reason I still find the Linux to be interesting… lsb_release might not be available. For that reason I use /etc/issue
There are many approaches for release information. Doing something with uname is another option. As I mentioned, the function itself isn’t that important. What matters are the concepts and ideas.
Completely understand… just a thought on the “Linux” requirements as I look for a job…. I like pwsh returning objects for things like installed packages… sudo apt list –installed | select-Object -Skip 1
I wish PSCore had Convert-FromString cmdlet with “TemplateContent” parameter to do the heavy lifting for converting string to objects