When running from cmd.exe
powershell .\scripts\scriptname.ps1
Which has a line to convert plain text to secure string
[securestring]$secString = ConvertTo-SecureString $SampleString -AsPlainText -Force
I get error:
ConvertTo-SecureString : The 'ConvertTo-SecureString' command was found in the module 'Microsoft.PowerShell.Security', but the module could not be loaded. For more information, run 'Import-Module Microsoft.PowerShell.Security'.
However if I open / run the script direct in powershell it runs fine?
If I try to import the module manually I get:
Import-Module : The following error occurred while loading the extended type data file: Error in TypeData "System.Security.AccessControl.ObjectSecurity": The member AuditToString is already present.
Error in TypeData "System.Security.AccessControl.ObjectSecurity": The member AccessToString is already present.
Error in TypeData "System.Security.AccessControl.ObjectSecurity": The member Sddl is already present.
Error in TypeData "System.Security.AccessControl.ObjectSecurity": The member Access is already present.
Error in TypeData "System.Security.AccessControl.ObjectSecurity": The member Group is already present.
Error in TypeData "System.Security.AccessControl.ObjectSecurity": The member Owner is already present.
Error in TypeData "System.Security.AccessControl.ObjectSecurity": The member Path is already present.
Powershell version is
Major Minor Build Revision
----- ----- ----- --------
5 1 22621 963
The symptom of your call to powershell.exe, the Windows PowerShell CLI, from cmd.exe (or a batch file) implies that you've launched cmd.exe from PowerShell (Core) 7+.
In other words: the chain of calls is:
pwsh.exe) -> cmd.exe -> Windows PowerShell (powershell.exe)This indirect call from PowerShell (Core) to Windows PowerShell is the problem: It makes the latter use the former's definition of the $env:PSModulePath and therefore results in attempts to load - incompatible - PowerShell (Core) modules.
Such an indirect call bypasses the logic that is built into PowerShell (Core) when directly invoking powershell.exe (dynamic removal of PowerShell (Core)-specific entries from $env:PSModulePath) and therefore requires a workaround:
Per GitHub issue #18530, the solution is to (temporarily) reset the PSModulePath environment variable:
:: From cmd.exe (a batch file).
set "PSModulePath="
powershell .\scripts\scriptname.ps1
Note:
As js2010 points out, when a process-specific value for PSModulePath is defined, powershell.exe uses this value as-is, which is problematic: unless the value includes the standard locations, required modules may not be discoverable.
By contrast, pwsh, the PowerShell (Core) 7+ CLI, is smarter about this: It automatically ensures the presence of all standard locations, even if a process-level value doesn't include them.
The exact rules for how the effective $env:PSModulePath value is determined are complex; they are documented as part of the conceptual about_PSModulePath help topic.
Note that even the default $env:PSModulePath values place the standard current-user module location first, making it possible to override standard cmdlets.
In both editions it is possible to place additional locations first:
implicitly, in Windows PowerShell, by defining a process-level value that determines the effective value as-is, as discussed.
explicitly, in PowerShell 7+, by including the current-user location in the process-level value, at the end.
To expand on the answer above, I needed to do the following. I was calling a PS 5 script from a PS 7 script and the called script contained ConvertTo-SecureString:
Start-Process -FilePath "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -NoNewWindow -ArgumentList "-File $script", $Parm1, $Parm2 -Environment @{PSModulePath = 'C:\Program Files\WindowsPowerShell\Modules;C:\Windows\system32\WindowsPowerShell\v1.0\Modules;C:\Program Files (x86)\ShareGate\'} -Wait
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With