PowerShellBuild
PowerShellBuild copied to clipboard
INIT task throws an exception in Windows PowerShell
Thanks for collecting so many PowerShell module build features in one place - I really appreciate this module and the well-thought collection of tasks/variables!
I spent a few minutes looking and didn't find any mention of the intended PowerShell version compatibility, so apologies if this has already been covered. I have a PowerShell 5.1 project that cannot be migrated to PowerShell 7, and the INIT task throws an exception when called from a Windows Powershell session.
I know it can add a lot of effort to maintain backward compatibility so I 100% understand if a conscious choice is made to forego support for Windows PowerShell / PowerShell 5.1. Since this looked to be the only barrier to using PowerShellBuild with my module I thought I'd ask.
Expected Behavior
PowerShellBuild tasks are compatible with PowerShell 5.1 as well as versions based on .NET 5+
Current Behavior
The following exception is thrown during the INIT task
Error: 9/7/2021 11:41:13 AM:
At ~\Documents\WindowsPowerShell\Modules\PowerShellBuild\0.6.1\psakeFile.ps1:19 char:5 + Initialize-PSBuild -UseBuildHelpers -BuildEnvironment $PSBPrefere ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [<<==>>] Exception: Method invocation failed because [System.IO.Path] does not contain a method named 'IsPathFullyQualified'.
Possible Solution
Out of an abundance of laziness, I switched from the IsPathFullyQualified()
method to IsPathRooted()
in Initialize-PSBuild.ps1
which is available in both PowerShell 5.1 and PowerShell 7. I know there's a difference between the two, so a better solution would probably involve creating a private function to reimplement the IsPathFullyQualified()
functionality in a way that is compatible between 5.1 and 7+.
Steps to Reproduce (for bugs)
- Create a new module with Stucco
- Execute .\build.ps1 from a Windows PowerShell terminal
Context
I'm refactoring the build process for a PowerShell 5.1 module which is a wrapper for an SDK based on .NET Framework. I already use psake and PowerShellBuild allows me to drop a lot of boilerplate. Once I modified the Initialize-PSBuild function it worked flawlessly.
Your Environment
- Module version used: 0.6.1
- Operating System and PowerShell version: Windows 10 with PowerShell 5.1
- Running .\build.ps1 from the Stucco template
I'm a bit new to BuildHelpers and PowerShellBuild, and trying to educate myself on how the build environments are constructed to understand what kind of paths you could potentially see in $BuildEnvironment.Build.OutDir, and if it's not fully qualified, how this block of code in Initialize-PSBuild.ps1
helps.
if ([IO.Path]::IsPathFullyQualified($BuildEnvironment.Build.OutDir)) {
$BuildEnvironment.Build.ModuleOutDir = [IO.Path]::Combine($BuildEnvironment.Build.OutDir, $env:BHProjectName, $BuildEnvironment.General.ModuleVersion)
} else {
$BuildEnvironment.Build.ModuleOutDir = [IO.Path]::Combine($env:BHProjectPath, $BuildEnvironment.Build.OutDir, $env:BHProjectName, $BuildEnvironment.General.ModuleVersion)
}
As far as I can tell, the $BuildEnvironment.Build.OutDir
path is constructed in build.properties.ps1
by combining $env:BHProjectPath and 'Output'. So ideally we end up with a path pointing to a subfolder of the current path named Output. If the path is fully qualified, then ModuleOutDir becomes BHProjectPath/Output/ProjectName/ModuleVersion.
If that path is not fully qualified, I'm not sure if the resulting path is as intended in all cases. Here are some examples from my Windows system and I had similar results from my ubuntu box
BHProjectPath IsFullyQualified ModuleOutDir
------------- ---------------- ------------
C:\repos\MyProject True C:\repos\MyProject\Output\MyProject\0.1.0
~\repos\MyProject False ~\repos\MyProject\~\repos\MyProject\Output\MyProject\0.1.0
.\repos\MyProject False .\repos\MyProject\.\repos\MyProject\Output\MyProject\0.1.0
C:Documents\repos\MyProject False C:Documents\repos\MyProject\Output\MyProject\0.1.0
repos\MyProject False repos\MyProject\repos\MyProject\Output\MyProject\0.1.0
../../repos/MyProject False ../../repos/MyProject\..\..\repos\MyProject\Output\MyProject\0.1.0
~/repos/MyProject False ~/repos/MyProject\~\repos\MyProject\Output\MyProject\0.1.0
It seems like under most circumstances, if the OutDir path is not fully qualified, you end up with a pretty funky ModuleOutDir. I'm assuming there are cases where OutDir is not fully qualified, and even if not, I'm for the belt & suspenders. What if instead of using "IsPathFullyQualified" we passed the $env:BHProjectPath through Resolve-Path
or [IO.Path]::GetFullPath()
in build.properties.ps1
when setting $BuildEnvironment.Build.OutDir
? Could we then get rid of the if-block and the .NET Core 2.1+ IsPathFullyQualified method?
I've solved the issue for my purposes with a minor modification and tests are passing. I don't think any sort of re-implementation of IsPathFullyQualified is necessary in this case, but I don't want to make a PR until you've had a chance to look at it.
I've run into this same issue. My project needs to run in Windows PowerShell because it is part of a JEA implementation. My project is compatible with pwsh so for now I'll build it there and assume the tests are valid for Windows Powershell, but it would be nice to fix this issue