OSS PowerShell: Platform Independent Functions
Just the other day Microsoft released PowerShell as open source with builds available for Windows, Mac OSX, and a few flavors of Linux. I’m pretty certain the entire community is super hyped at the news. I know I am!
I was able to quickly get PowerShell running on my Mint 17.3 (Rosa) workstation (Based on Ubuntu 14.04) in about 2 minutes flat using the included documentation. From here I was able to start up the shell and start using all the basic commands I’ve been using for years. But I soon realized that a large portion of my code would be useless on a Linux platform. The differences between Linux and Windows are pronounced enough that I can immediately list out some code that will cause compatibility issues. This includes:
- Anything that references statically defined paths (think drive letters and such which do not exist on Linux)
- Anything which relies on external DLLs
- Anything which relies on WMI (generally is only on Windows and only targets Windows specific implementations of CIM/WBEM)
- Most anything which uses Add-Type or other .NET type definitions. You will need to ensure compatibility with the .Net Core namespaces. There are some tools for doing this for more hardcore developers. You may have some luck by searching here for parts of your type definitions to see if it is available in .Net Core yet.
- Pretty much anything ‘Windows-centric’. An example would be get-service. Yes, Linux and OSX has the concept of services/daemons but these are not the same as Windows services so Get-Service doesn’t work. I expect soon there will be wrapper functions available for SystemD (systemctl) and other service management frameworks but currently many of the native windows commands simply don’t work.
Cross-Platform Functions
So how would you make a cross-platform capable function? That is a great question which you can gleam a bit of insight from simply by looking at the whopper of a build script module included with OSSPosh (my newly coined term for the project). Here is the first part of the module:
That looks pretty easy to use, so lets go ahead and do so! Here is a quick function to get things started. This function will let you know what platform you are running on.
Here is how you might use the above function to write a generic function for getting the current IP address of the system you are on.
This is kind of a silly example but should get the point across. I’m essentially using two different methods to get the same information (a great improvement exercise for the reader would be to use the GetAllNetworkInterfaces first then filter based on name or something based on the platform and eliminate the Get-WMIObject entirely).
Some Other Notes
If you want a quick Linux box of your own to try things out on here are my fast setup commands using vagrant with virtualbox (BTW, if you don’t already use chocolatey you can use this excellent app to get these two programs installed in record time on your workstation).
I went ahead and installed OSSPosh (Or just PowerShell 6 if you prefer?) on my Windows 10 workstation as well. This installed quickly and without interfering with my current PowerShell profile or paths. You can quickly tell if you are in the Core or Desktop edition by taking a peek at the $PSEdition variable.
Interestingly enough the Powershell profile path is different. The desktop edition of Powershell (5.0) points where you would expect it to:
In the core version of PowerShell it points to a more platform agnostic path:
What I’m still trying to figure out is why the core edition loads different modules on my workstation than on my Linux box. There is a difference somewhere that I’ve yet to isolate but I’m sure will become clear soon enough.
A Bug? (Update)
I’ve noticed a bug when using some native Linux commands from a Powershell console when connected to the host via SSH. It seems to hang the shell (or cause it to act sporadic and delayed). Currently aliases for ls, ps, and others are not set as the Posh team figures out the best way to go with this one. Simply setting some of these in the profile before loading the console seems to avert the issue for now. After connecting to your host via ssh do the following to create a profile script
Then add in a few aliases like so:
I’d use a tool like screen or tmux before loading the shell so you can kill it if things go wonky on you for whatever reason.
Final Thoughts
I’m sure there are cleverer ways to get things like this done and I expect them to emerge in the coming months. Until then you may want to start thinking of modules you have written and seeing if they are good candidates for becoming cross-platform. This is exciting times for us cross-platform geeks. We are getting bash on Windows, Powershell on Linux, what next? I don’t know but I’m looking forward to seeing where things go!