Ironman Software Forums
Continue the conversion on the Ironman Software forums. Chat with over 1000 users about PowerShell, PowerShell Universal, and PowerShell Pro Tools.
This is probably one of the most frequently asked questions about PowerShell Universal. Why doesn’t my script work the same in PowerShell Universal as it does in a PowerShell prompt? This post provides some context and steps you can take to help identify issues that may occur when running your scripts in the platform.
You need to be aware of the versions that are in play when running scripts in PowerShell Universal. It’s easy to select different versions of PowerShell so make sure you are running the script in the expected version.
The versions of PowerShell are listed in the Platform \ Environments page. When you update PowerShell 7, PowerShell Universal will automatically use the one that is at the default path. It’s also possible to install PowerShell 7 versions side-by-side and configure PowerShell Universal to use multiple versions.
One common problem here is with modules that do not work natively in PowerShell 7. When this is the case Windows PowerShell Compatibility will kick in. It will appear to work as expected but, in the background, new Windows PowerShell processes will be starting. Every runspace the uses the Windows PowerShell module in the PowerShell 7 environment, will start a new process. This can reduce performance considerably.
The integrated environment is a version of the PowerShell 7 SDK that is built into PowerShell Universal. It does not change when upgrading PowerShell on the host machine. It only changes when a new version of PowerShell Universal upgrades the version of the PowerShell SDK.
The integrated environment is fast because it doesn’t require starting external processes or communicating across an RPC channel. The downside of the integrated environment is that it’s a single point of failure for all scripts, APIs and dashboards as they share the same process space. It also means that you may run into assembly conflicts when loading many modules that use common .NET assemblies.
This is frequently the case for the
NewtonSoft.Json library. Scripts that use built-in modules or no modules at all are great candidates for use in the integrated environment.
Running a script as a local user on a machine can be vastly different than running a script in PowerShell Universal when it’s hosted as a service or within IIS. You need to be aware of where your modules are installed because PowerShell Universal may not discover them in the same place.
Additionally, if you’re hosting as a service and the module needs to interact with the desktop (like Selenium), you’ll have to take extra care when configuring the service.
IIS restricts the application pool’s user even further by limiting the privileges the account has when running. This means that access certain directories or elevating to another user account can cause issues even if the user is an administrator. One example of this is that
New-WebServiceProxy does not work in IIS because the cmdlet attempts to write C# files and compile them from disk and the app pool does not have the privilege.
You can use the Terminal feature of PowerShell Universal to investigate the environment you currently have configured to see what the differences are.
PowerShell Universal has two custom hosts. The first is used when running scripts as jobs. This host has features such as waiting for feedback and outputing to various streams. The second is used for all other operations within PowerShell Universal. It doesn’t implement any custom host features besides logging.
If you happen to forget parameters or prompt for feedback from the user, with something like
Read-Host, in a host that doesn’t support it, you will receive errors. It’s best practice to avoid this type of interaction when working in PowerShell Universal.
PowerShell Universal uses runspace pools to perform most functionality within the system. It will create runspaces when needed and dispose of them when they aren’t. After each execution of a function, like an API or a dashboard endpoint, the runspace state will be reset.
This can have an effect on scripts that use features of PowerShell like sessions or remoting. You won’t be able to use sessions across endpoint calls unless you enable the persistent runspace feature.
PowerShell Universal is designed to run for an extended period of time. We take steps to clean up resources periodically and recycle runspaces after a set number of uses or some amount of time. Some PowerShell modules are not well designed for this type of execution environment. They expect to run in a PowerShell process that invokes a script and then terminates.
To help work around this issue, you can run scripts as jobs in external processes to ensure that all resources are cleaned up after the script has finished. Certain modules such as PowerCLI and dbatools have static .NET classes that can maintain state and consume memory even when runspaces are disposed and .NET garbage collection is run.
IIS can provide recycling features that will restart the PowerShell Universal process on intervals, when certain resource consumption limits are hit or when the server is not being used.
PowerShell Universal’s secret management implementation is based on the Microsoft Secret Management modules. It includes the core module along with several vault modules in the default installation.
All of the default included vaults implement user-specific storage mechanisms. If you change the user account of the PowerShell Universal service, you will no longer be able to access secrets. This also means that if you create secrets in your local environment as your own user, it’s likely that PowerShell Universal will not be able to access those secrets.
Hopefully this post has provided some context to help identify issues you may have running scripts in PowerShell Universal. Have you run into another issue you think that should be mentioned? Make sure to chime in on the discussion linked above.