Users

All Posts (970)

avatar

Patrick Ouimet

Job timout issue

avatar
avatar
avatar

Hello Michael,

Thank you for the answers, the log excerpt and the screenshot, they help a lot.

To answer your question, this does not look like a collision where one job blocks the other.

It looks more like both jobs were caught in the same startup rush.

Your screenshot shows it well, since DHCP\Get-Scopes.ps1 and Boarding\Get-TerminatedEmployees.ps1 are child jobs of two different schedules, yet both started at 12:00:36 AM and both failed within a second of each other at 12:03 AM.

Two different scripts failing at the same second points to the server being busy at that moment, not to anything in the scripts themselves.

In the PowerShell 7 environment, each job starts its own PowerShell process, and that process must check in with the server before the Job Handshake Timeout runs out.

At midnight, your midnight schedules, up to 15 of them, start together, and Process-DHCP-Data and BHR Term Process then start their child jobs on top of them.

On a single node, all of these new processes compete for CPU, disk and security scanning at the same time, so a few of them can miss the 120 second window.

This would also explain why the failures look random, and why a re-run works once the server is quiet again.

Here is what we suggest to spread the load:

  • Turn on Random Delay for the midnight schedules, so each one starts at a random point within 60 seconds instead of all at once: https://docs.devolutions.net/powershell-universal/automation/schedules

  • For a wider window, add both -RandomDelay and -RandomDelayMaximum to those New-PSUSchedule lines in .universal\schedules.ps1, for example 300 for up to five minutes.

  • If the timing allows, move the BHR Term Process and Process-DHCP-Data schedules away from midnight and away from each other, for example to 12:15 AM and 12:30 AM, so their child jobs do not start in the same rush.

  • In the parent scripts, add a short pause between child job launches so they do not all start in the same second.

  • Keep the PowerShell Universal folders and executables excluded in your EDR, as listed in the Antivirus Configuration section I shared earlier.

Even when the EDR blocks nothing, scanning a new process can slow its start without leaving a block event.

For the logs, you do not need to create an account.

You can simply reply to our email from service@devolutions.net with the subject "00135551: Logs" and attach the file there, zipped if it is large.

The most useful file now is the full System log for November 1, from %ProgramData%\PowerShellUniversal\Logs\System.

It will show what the server was doing between midnight and 12:04 AM, and how many jobs it was starting at that moment.

If you can, please also tell us:

  • The number of CPU cores and the amount of memory on the server.

  • Whether these failures only happen around midnight, or also in your 6 AM and 8 AM slots.

  • Whether a SQL Server backup or maintenance task runs around midnight.

Best regards,

Code Folding in VSCode using the Devolutions PowerShell Universal Extension 2026.3.3 is not working.

avatar
avatar
avatar

Hello Finn,

Thank you for narrowing this down, your test pointed us straight at the cause.

Yes, this is an interaction between the two extensions, and the fix belongs on our side, in the PowerShell Universal extension.

We reproduced the issue and confirmed what causes it.

For files opened through the PowerShell Universal connection, our extension asks the Microsoft PowerShell extension to work out the folding regions.

That hand-off currently returns no regions, so VS Code shows no folding arrows.

When the Microsoft extension is disabled, our extension skips that step and VS Code uses its standard indentation-based folding instead.

That is why folding works in your separate profile.

I have reported it to our development team (ticket PSU-1619, for internal reference only).

Updating the extension to 2026.3.4 will not change this, since the folding code is the same in that version.

In the meantime, you have two options.

Your separate profile works well for editing.

Please note that it has none of the Microsoft PowerShell extension features, such as attaching the debugger to PowerShell Universal runspaces.

Or if you prefer to keep both extensions in one profile, add this to your VS Code settings.json:

"[powershell]": {

"editor.foldingStrategy": "indentation"

}

We tested it with both extensions enabled, and the folding arrows and Fold All work again on PowerShell Universal files.

It also applies to your local PowerShell files, which will then fold by indentation instead of by syntax.

You can find more details on folding options here: https://code.visualstudio.com/docs/editing/codebasics#_folding

I will update you as soon as a fix is planned.

Best regards,

Job timout issue

avatar
avatar
avatar

Hello michaelhanson1458,

Unfortunately, we didn't receive any logs or any new cases related to your email.

I will open a new case and send you a secure link to share your logs.

Best regards,

Upgrade change Install Directory

avatar
avatar
avatar

Hello,

Thank you for the clear description, it made the cause easy to find.

What you saw comes from the way the PowerShell Universal installer handles upgrades.

When the new MSI runs through its setup wizard, it does not reuse your custom folder.

It installs to the default C:\Program Files (x86)\Universal folder instead.

During the same upgrade, Windows Installer removes the old version and its whole folder.

This is why D:\Apps\Universal was deleted.

Your settings and data are kept, because by default they are stored under C:\ProgramData and not in the install folder.

If you kept any of your own files inside D:\Apps\Universal, please restore them from a backup.

For future upgrades, run the MSI from an elevated command prompt and pass your folder with the INSTALLFOLDER property:

msiexec /i "C:\Temp\Devolutions.PowerShellUniversal.<version>.msi" INSTALLFOLDER="D:\Apps\Universal" /qn /norestart /l*v "C:\Temp\psu-upgrade.log"

The silent switch (/qn) is needed here, because the setup wizard resets the folder to the default even when INSTALLFOLDER is set.

Your existing appsettings.json is not replaced, the installer only creates it when it is missing.

If the PowerShellUniversal service runs under a dedicated account, also add SERVICEACCOUNT and SERVICEACCOUNTPASSWORD to the command.

The Update-PSUServer cmdlet has no folder option and always uses the default folder, so please use msiexec for now.

If there is no rush, you can wait for the next release and upgrade with the command above, which moves it back to D:\Apps\Universal.

To move your current 2026.3.4 install back right away, uninstall it first.

Then reinstall 2026.3.4 with the same command.

The uninstall step is needed because the installer does not allow an upgrade to the same version.

As a precaution, back up C:\ProgramData\UniversalAutomation and C:\ProgramData\PowerShellUniversal before you uninstall.

After the move, update anything that still points to the old path, such as firewall rules or antivirus exclusions for Universal.Server.exe.

You can find all installer properties on our installation page:

https://docs.devolutions.net/powershell-universal/getting-started

I am also sharing this upgrade behavior with our development team, so the wizard can keep the existing folder in a future version.

Best regards,

Alberta Time Zone Change

avatar
avatar
avatar

Hello ashrafulalam,

Thank you for the clear description and the screenshots.

We reproduced the issue in our lab, and your PSU settings are correct.

Alberta moved to UTC-6 all year on November 1, 2026, and Windows added a new time zone for it, "(UTC-06:00) Mountain Time (Alberta)".

On Windows, PowerShell Universal turns a time zone name like America/Edmonton into a Windows time zone.

Windows still matches America/Edmonton to the older Mountain Standard Time zone, which went back to UTC-7 on November 1.

Because of this, schedules set to America/Edmonton run one hour late, and the admin console shows times one hour behind.

Restarting the service does not change this.

For the schedules, please change the time zone from America/Edmonton to America/Regina.

America/Regina is the Saskatchewan time zone, which is also UTC-6 all year, so the run times will match Alberta time.

You can pick it in the same Time Zone list on each schedule.

In our test, a daily schedule set to 9:28 with America/Regina ran at 9:28 Alberta time, while the same schedule with America/Edmonton ran at 10:28.

Your schedules that run every 10 minutes are not affected, since they keep running every 10 minutes.

The admin console takes its time zone from your browser, which reports America/Edmonton, and the server reads it the same way.

You can see this on your User Settings page, where Time Zone shows "(UTC-07:00) Mountain Time (US & Canada)".

There is no setting to change this in the console, so the times shown there will stay one hour behind until a fix is available.

We are passing this to our development team so that PSU handles the new Alberta time zone correctly.

If you want to confirm it on your server, you can run these two lines in PowerShell 7 (pwsh.exe), not in Windows PowerShell 5.1:

[System.TimeZoneInfo]::FindSystemTimeZoneById('America/Edmonton').GetUtcOffset([DateTime]::UtcNow)

[System.TimeZoneInfo]::FindSystemTimeZoneById('America/Regina').GetUtcOffset([DateTime]::UtcNow)

On an affected server, the first line shows -07:00 and the second shows -06:00.

Could you let us know your PowerShell Universal version, so we can follow the fix for it?

You can find more about schedules here: https://docs.devolutions.net/powershell-universal/automation/schedules/

Best regards,

2026.3.4 - Regex POST and PATCH APIs Not Working When App at Root

avatar
avatar
avatar

Hello Sunny,

Thank you for testing 2026.3.4 so quickly, and for the clear steps to reproduce it.

We reproduced the issue in our lab on 2026.3.4, and the log you sent shows the same result on your server.

When an app is hosted at the root ("/"), regex endpoints that accept POST, PATCH or DELETE get an HTTP 405 (Method Not Allowed) with an empty body.

That empty 405 is the blank response you see.

The web routing hands the request to the app at the root before PowerShell Universal checks its regex endpoints, and that app only accepts GET.

GET requests to regex endpoints are not affected, which is why the 2026.3.4 fix looks partial.

It also explains your Invoke-PSUEndpoint result, because that cmdlet runs the endpoint inside PowerShell Universal and skips the web routing.

The GET in your log is a separate request, sent about 13 seconds before the POST.

The app at the root answered it, signed the user in with Windows authentication, and returned the app page.

The POST was not turned into a GET, and it received the 405 directly.

I am reporting this to our development team with our lab results and your log, as a follow-up to the earlier regex issue (ticket PSU-283, for internal reference only).

Moving the app away from the root still works, and we confirmed it in the lab.

If the app needs to stay at the root, there is a second workaround that we also confirmed.

Standard endpoints, without the Regex setting, accept POST, PATCH and DELETE normally when an app is at the root.

Your example URL has no regex pattern in it, so you can define it as a standard endpoint with a leading slash, and keep everything else the same:

$Var = @{ URL = '/my/api/v1/Computer/Request'; Method = @('POST','PATCH','DELETE'); Environment = 'Dedicated - API - v1'; Description = "Request API"; Authentication = $True; Role = @('Administrator', 'Requestors'); Path = "D:\Powershell Universal\Endpoints\myendpoint.ps1" }

New-PSUEndpoint @Var

In our lab, this endpoint worked next to your regex GET endpoint on the same base path.

If a write URL needs a variable part, the colon syntax also worked, for example /my/api/v1/Computer/:Id/Update.

You can find the syntax here: https://docs.devolutions.net/powershell-universal/api/endpoints/

Your GET endpoints that use regex can stay as they are.

One more point from your log: the account my\jsundberg3 received only the Reader role, while this endpoint allows Administrator and Requestors.

Please check that the account that calls the endpoint has one of those two roles.

Best regards,

Restricting access to edit a script "Execution Role"

avatar
avatar
avatar
avatar

Hello Malcolm,

Thank you for following up.

I understand this is blocking you from adding secrets for your vendors and partners.

There is no change in the current releases yet.

A user who can edit a script can still set its Execution Role to a role they are not a member of.

That script can then read any secret protected by that role.

This is a current product limitation, and our development team is tracking an improvement for it (ticket PSU-1227, for internal reference only).

The goal of this implementation is to control who can give extra rights to a running script.

We do not have a confirmed release date or final design to share yet.

I will update this thread as soon as we can confirm what it covers and when it ships.

Your suggestion about Job Output visibility was shared with the development team as part of the same request.

Until then, the safest approach is to treat script edit rights as access to every role-protected secret on that instance.

Here are two ways to keep your vendor and partner secrets isolated today.

Only give script create or edit rights to authors who are allowed to see every role-protected secret on that instance.

  • Keep the vendor and partner secrets on a separate PowerShell Universal instance, where only the cleared authors can create or edit scripts.

  • Authors who should not see these secrets can hand their scripts to a trusted author, who reviews and publishes them.

Also keep in mind that anyone who can edit a script that already runs with a privileged role can use that role through the script's code.

Limiting edit rights on those scripts matters as much as limiting who can assign the role.

You can find more details on secret roles and permissions here.

https://docs.devolutions.net/powershell-universal/platform/variables

https://docs.devolutions.net/powershell-universal/security/enterprise-security/permissions

Best regards,

Logging - User\Process correlation within logs

avatar
avatar
avatar

Hello Allan,

Thank you for the update and for confirming your version.

Before replying, I tested the whole chain on a 2026.3.3 server, and I need to correct one point from my first example.

Leave out -Integrated when you call Invoke-PSUScript from an app or an API.

In 2026.3.3, the default security model is Strict.

In that mode, PowerShell Universal blocks calls that use -Integrated with "Permission denied", even for administrators.

Without -Integrated, the call runs as the signed-in user or the API caller, and it worked in all three security models.

That user needs permission to run the script, and the API endpoint needs authentication turned on.

This also applies to the app example from my first reply, so remove -Integrated there and keep the rest.

Your plan to pass the ID to the API in a header is a good fit.

APIs have a few built-in variables that help here.

$Headers holds the request headers, but lookups in it are case-sensitive.

Copy it into a hashtable first, as in the example below, so the header name matches in any case.

$RequestId holds a unique ID for each request, so you can use it when the header is missing.

$Identity holds the name of the caller.

If the app calls the API with a shared app token, $Identity shows the account that owns that token, not the person who clicked.

In that case, send the app user in a header as well.

Here is the endpoint example, tested on 2026.3.3:

# $Headers is case-sensitive, a PowerShell hashtable is not

$RequestHeaders = @{}

foreach ($Key in $Headers.Keys) { $RequestHeaders[$Key] = $Headers[$Key] }

$CorrelationId = $RequestHeaders['X-Correlation-Id']

if (-not $CorrelationId) { $CorrelationId = $RequestId }

$CallingUser = $RequestHeaders['X-Calling-User']

if (-not $CallingUser) { $CallingUser = $Identity }

Write-PSULog -Feature 'API' -Resource '/report' -Level Information -Message "CorrelationId=$CorrelationId User=$CallingUser RequestId=$RequestId received"

$Job = Invoke-PSUScript -Name 'Script1.ps1' -Parameters @{

CorrelationId = $CorrelationId

CallingUser = $CallingUser

} -Notes "API=/report User=$CallingUser CorrelationId=$CorrelationId"

New-PSUApiResponse -StatusCode 200 -Headers @{ 'X-Correlation-Id' = $CorrelationId } -Body (@{ CorrelationId = $CorrelationId; JobId = $Job.Id } | ConvertTo-Json)

The endpoint sends the ID back in a response header, so the caller can log the same value.

The -Notes value also stores the ID with the job.

In my tests, the API line and the script lines with the same ID all landed together in the default User log file.

I will also share your use case with our product team as a request for a built-in correlation ID.

Let me know if you have any other questions, otherwise I will close this case in a few days.

Here are the related pages:

https://docs.devolutions.net/powershell-universal/platform/variables

https://docs.devolutions.net/powershell-universal/development/logging

https://docs.devolutions.net/powershell-universal/config/module

https://docs.devolutions.net/powershell-universal/powershell-commands/new-psuapiresponse

Best regards,

Job timout issue

avatar
avatar
avatar

Hello Michael,

Thank you for the details, having the exact error text helps a lot.

This error comes from the job handshake, the moment PowerShell Universal starts a new PowerShell process for a job and waits for that process to report that it is ready.

That wait covers only the process startup, not your script.

So a 120 second stall means something is slowing down or blocking the launch of the process on the server.

Since your Job Handshake Timeout is already at 120 seconds, four times the default of 30, raising it again is unlikely to solve this.

The next step is to find what holds the process back.

To reduce the failures in the meantime, here are two things you can do now:

To find the cause, could you email the following to service@devolutions.net instead of posting it here?

Logs can contain server names, paths and account names, and email keeps them out of this public thread.

Please include a link to this thread in your email so we can match it to your request.

  • The system log that covers one failed job, from %ProgramData%\PowerShellUniversal\Logs\System, with the time of the failure.

  • Whether the failing jobs use a Run As credential, and which environment they run in, for example PowerShell 7 or Windows PowerShell 5.1.

  • Whether PowerShell Universal runs as a Windows service or under IIS, and how many nodes share the SQL database.

  • Roughly how many jobs start at the same time when the failures happen, and whether the failures cluster at certain times or on one node.

  • When this started, and whether anything changed around that time, such as an upgrade, an antivirus update, new schedules or server changes.

The system log tells us whether the PowerShell process exited early or never answered, and each case points to a different cause.

Once we have this, we can narrow down where the startup time goes.

Best regards,

Git discard all changes 2026.3.4

avatar
avatar
avatar

Hello Dy,

Thank you for the detailed report and for the screenshots.

The RoleService errors about built-in roles are a known issue (ticket PSU-1507, for internal reference only).

PowerShell Universal logs them when it reloads the full configuration, and the built-in roles are not deleted.

They are not related to your pending changes, so you can ignore them for now.

For the Discard all & stop editing button, your screenshots show that most of the 352 changes are new files, such as the module folders under Modules.

Our working theory is that Discard all reverts changed files but does not remove newly added files.

That would explain why the list looks the same after the redirect.

To help us confirm it, could you check the following after you click Discard all & stop editing?

  • Does the change count stay at exactly 352, or does it go down a little?

  • Are the remaining items all marked A (added), or do some show as modified?

  • Which Git sync mode do you use, and is the external Git client option turned on?

Could you also share the system log lines from the same minute, including the INF lines?

Best regards,

creating Rate Limits bug 26.3.3

avatar
avatar
avatar
avatar

Hello Dy,

Here is a quick update on the empty Rate Limits list.

We have now reported the issue to our development team.

The report covers the duplicate rate limit name that keeps the page loading.

It also covers the admin console accepting a name that is already in use.

We will update this thread when a fix is planned.

While testing, we found one more thing you may want to check.

On version 2026.3.3, the 1 Day option in the rate limit form saves a period of 24 days and 1 second.

If you used that option, the Rate Limits list shows its period as 24.00:00:01.

You can correct it by changing that rule's period to 1.00:00:00 in ratelimits.ps1 and clicking Save.

The workaround and the duplicate check from my previous reply still apply.

If the list goes empty again, the system log from that moment would still help us find what slowed the save.

Best regards,

Logging - User\Process correlation within logs

avatar
avatar
avatar

Hello Allan,

Thank you for the clear question.

You are not missing anything.

PowerShell Universal does not add a shared correlation ID that links an app event to the job it starts.

Apps and jobs write their own log lines, so your code has to carry the link.

All the pieces you need are available as built-in variables.

In an app, $User holds the signed-in user and $DashboardName holds the app name.

In a script, $UAJob.Id holds the job ID and $UAJob.Identity.Name holds the user who started the job.

The simplest pattern is to create an ID in the app, pass it to the script, and write it in every log line on both sides.

Here is the app side:

New-UDButton -Text 'Run report' -OnClick {

$CorrelationId = [guid]::NewGuid().ToString()

$Job = Invoke-PSUScript -Name 'MyScript.ps1' -Integrated -Parameters @{

CorrelationId = $CorrelationId

CallingUser = $User

} -Notes "App=$DashboardName User=$User CorrelationId=$CorrelationId"

Write-PSULog -Feature 'App' -Resource $DashboardName -Level Information -Message "CorrelationId=$CorrelationId User=$User App=$DashboardName started job $($Job.Id)"

}

Here is the script side:

param(

[string]$CorrelationId,

[string]$CallingUser

)

Write-PSULog -Feature 'Script' -Resource 'MyScript.ps1' -Level Information -Message "CorrelationId=$CorrelationId User=$CallingUser Job=$($UAJob.Id) started"

# ... your work ...

Write-PSULog -Feature 'Script' -Resource 'MyScript.ps1' -Level Information -Message "CorrelationId=$CorrelationId User=$CallingUser Job=$($UAJob.Id) finished"

You can then search for that ID in Observe > Logging > Live Logs, or in the User log file, to see the app line and the script lines together.

The -Notes value is also stored with the job, so the run itself carries the app, the user and the ID.

If you add -Wait, the cmdlet returns the script output instead of the job object, but the shared ID still links both sides.

A few tips will save you time:

  • Pass $User from the app as a parameter, instead of relying on $UAJob.Identity, so the script always sees the person who clicked.

  • Put the values straight into -Message with normal PowerShell string expansion, as in the example.

  • The -Properties parameter is accepted, but its values do not show as separate fields in the built-in log view, so string expansion is the safer choice for now.

  • If you send logs to a File, Database, TCP or HTTP target, set its Scope to User so the Write-PSULog lines reach it.

Could you tell me which PowerShell Universal version you are running?

Version 2026.2.4 fixed some cases where Write-PSULog lines went to the system log instead of a User target (tickets PSU-947 and PSU-296, for internal reference only).

Knowing your version lets me confirm the example behaves the same way on your server.

Here are the related pages:

https://docs.devolutions.net/powershell-universal/development/logging

https://docs.devolutions.net/powershell-universal/platform/variables

https://docs.devolutions.net/powershell-universal/powershell-commands/write-psulog

https://docs.devolutions.net/powershell-universal/powershell-commands/invoke-psuscript

Best regards,

2026.3.3 workflowname that ends with whitespace

avatar
avatar
avatar

Hello Denis,

Thank you for the report and for the follow-up about the schedules.

I looked into both issues and I can confirm the cause of each one.

The first issue happens because PowerShell Universal saves the workflow name exactly as typed, including a trailing space.

The link on the Workflows page drops that space, so the workflow page looks for a name that does not exist and shows "Not Found".

The second issue is related.

A schedule stores the name of its workflow, and renaming a workflow does not update the schedules that point to it.

Until the service restarts, the schedule still fires at the right time, but it cannot find a workflow with the old name, so no job starts.

Each missed run writes a "Workflow <old name> not found." error to the server log.

After a restart, the schedule is no longer loaded for that workflow, which is why it showed an empty workflow.

To fix a workflow name that ends with a space, you do not need to open the workflow page.

Go to the Workflows page.

Click the More Actions (…) menu at the end of the workflow row.

Select Edit Properties, remove the trailing space from the name, and save.

Since this is also a rename, please re-link the schedules of that workflow afterwards, the same way you did before.

To find any schedule that still points to a workflow name that no longer exists, you can run this from a PowerShell Universal script or after Connect-PSUServer:

$workflowNames = (Get-PSUWorkflow).Name

Get-PSUSchedule | Where-Object { $_.Workflow -and $_.Workflow -notin $workflowNames } | Select-Object Id, Name, Workflow

You can then re-link each one with Set-PSUSchedule -Id <Id> -Workflow '<new name>'.

I am reporting both issues to our development team, and I will let you know when a fix is available.

Best regards,

2026.3.3 Bug when updating scripts.ps1

avatar
avatar
avatar

Hello,

Thank you for the detailed report on the forum.

I am glad that removing and recreating both scripts cleared the problem for now.

I would still like to reproduce it on our side so it can be fixed for good.

From what I can see, PowerShell Universal rewrites the whole scripts.ps1 file each time a script is added or removed in the admin console.

That means the wrong name and description were already stored on the Register-DnsRecord.ps1 entry before the file was written.

To find out how that entry got mixed up, could you share the following?

If your repository is in Git, the scripts.ps1 history from before your manual cleanup, ideally the first commit where the Register-DnsRecord.ps1 entry shows the wrong name.

The top of both script files, in particular any [DisplayName()] attribute or comment-based help block.

How Register-DnsRecord.ps1 was first created: with New Script in the admin console, by copying Unregister-DnsRecord.ps1 on disk, or another way.

Whether both scripts sit in the same folder, and whether a Script Base Folder is set.

Your hosting type (Windows service, IIS or Docker) and your database (SQLite or SQL Server).

If the problem comes back, please save a copy of scripts.ps1 before you fix it.

That copy shows us the bad state directly.

Until then, keeping scripts.ps1 in Git, or taking a quick backup before you add or remove scripts, makes recovery much easier.

Here is how script names and comment-based help are handled in PowerShell Universal: https://docs.devolutions.net/powershell-universal/automation/scripts

Best regards,

Reload all configurations failure with endpointdocumentation

avatar
avatar
avatar

Hello Romano,

Thank you for the detailed follow-up and the sample files, which made this much easier to trace.

The SQLite error does not come from your SQL Server database or from your SQLite database file.

PowerShell Universal keeps the resources it reads from the .universal files in a separate in-memory SQLite store.

That is why you see a SQLite error on both machines, and why your own database shows no endpoint or documentation rows.

Here is what happens during Reload All Configurations on 2026.3.3.

PowerShell Universal first reloads the repository's own endpointDocumentation.ps1 file.

Your documentation entries come from your modules, not from that file, so the reload treats them as removed and tries to delete them.

Your module endpoints still point to those entries through their Documentation parameter, so the store blocks the delete.

That blocked delete is the foreign key error in your log.

Because the delete is blocked, your documentation entries stay in place, which matches what you saw.

PowerShell Universal 2026.3.4, now available, changes this behavior.

A repository reload now leaves resources that belong to a module alone, and each module reload manages its own resources.

In the release notes, this fix is listed as "Fixed external modules disappearing after Git synchronization changes": https://devolutions.net/powershell-universal/release-notes/

The same change also covers manual reloads such as Reload All Configurations.

Could you upgrade your dev machine to 2026.3.4 and run Reload All Configurations again?

Please let me know whether the error is gone.

If it still appears, send me the new log entry and I will reproduce it on our side with your sample module.

Until then, the error does not remove anything, so you can leave it as is.

A restart remains the cleanest way to pick up module changes on 2026.3.3.

Endpoint documentation is described here: https://docs.devolutions.net/powershell-universal/api/openapi

Best regards,

Reload all configurations failure with endpointdocumentation

avatar
avatar
avatar

Hello Romano,

Thank you for the report and for including the full stack trace.

The trace shows what fails, even if it does not yet show why.

During a full reload, PowerShell Universal reads endpointDocumentation.ps1 again.

It then tries to delete a documentation entry that it no longer finds.

The database blocks the delete because some endpoints still point to that entry.

Our working theory is that the documentation from your modules looks missing to the full reload.

Module resources are loaded when the service starts, so the reload may not see them.

We have not confirmed this yet, so I would like to reproduce it on our side.

Could you send the following?

The exact PowerShell Universal version on the IIS server and on your dev machine.

Whether the IIS server also uses the default SQLite database, or SQL Server or PostgreSQL.

Where New-PSUEndpointDocumentation is called: in each module's .universal folder, in the repository's own .universal folder, or in both.

A trimmed copy of one module's endpoints.ps1 and endpointDocumentation.ps1, with only the New-PSUEndpoint and New-PSUEndpointDocumentation lines (names and URLs can be masked).

Whether the error also appears after a clean restart, or only after Reload all configurations.

Whether you see any impact beyond the log entry, for example missing endpoints or missing Swagger pages.

In the meantime, a restart is the safer way to pick up module changes.

On IIS, that means recycling the application pool.

On your dev machine, it means stopping and starting Universal.Server.exe.

The module documentation explains that module resources are loaded at startup: https://docs.devolutions.net/powershell-universal/platform/modules

For reference, endpoint documentation is described here: https://docs.devolutions.net/powershell-universal/api/openapi

Best regards,

Export Passkey

avatar
avatar
avatar
avatar
avatar

Hello cyraxan,

Thank you for this feedback.

Unfortunately, the PassKey cannot be exported or imported.

To create a new key in DVLS, I suggest following the documentation and creating a new PassKey.

https://docs.devolutions.net/password-manager/knowledge-base/browser-extension-knowledge-base/passkeys

Best regards,

creating Rate Limits bug 26.3.3

avatar
avatar
avatar
avatar

Hello Dy,

Thank you for confirming those details.

You are right, a rule on /api/v1/myendpoint only counts requests to that method and path.

It does not slow down your other endpoints or the admin console.

The warning in our documentation means the rate limiter checks every request the server receives, including the management API.

So a broad rule, such as * or /api/v1/*, would also throttle the admin console.

A rule scoped to one path, like yours, is safe.

One tip: your endpoint shares the /api/v1/ prefix with the management API.

If you later add a wildcard rule for your own APIs, a different prefix would keep the admin console out of its scope.

You also found that pasting the same line back fixed the issue.

That tells us the rule itself is valid.

The problem was most likely the state left behind by the save that hung.

Two details would help us narrow this down.

In your first post you mentioned ratelimits.ps1, and in your second post endpoints.ps1.

Could you confirm which file held the New-PSURateLimit line when the list was empty?

Also, does this instance use Git sync, and did it have pending changes at that time?

If it happens again, the checks from my previous reply will give us what we need to report it to the development team.

You can find more details on rate limits here:

https://docs.devolutions.net/powershell-universal/api/rate-limiting

Best regards,

Groom Jobs Do Not Complete and Scheduler stops processing until restarted

avatar
avatar
avatar

Hello,

Thank you for the detailed report.

The screenshots and the debug log line up with a known issue in PowerShell Universal 5.5.x.

The groom job locks the job queue table while it cleans it up.

When one groom run has not finished before the next one starts a minute later, the locks pile up and the runs never complete.

Each stuck groom run holds one Hangfire worker, and once all 100 workers are held, no other job can start.

Your screenshots match this pattern closely.

The restart was logged at 16:06, and the last scheduled job finished at 5:43 PM, about 100 minutes later.

That is one stuck groom run per minute until all 100 workers were taken.

The fix was released in PowerShell Universal 5.5.4, under the Platform fixes in its release notes.

We recommend upgrading the development server to the current PowerShell Universal release rather than stopping at 5.5.4.

Later releases also stop overlapping groom runs from logging misleading concurrency warnings.

Before you upgrade, back up the database and appsettings.json as described in the upgrade guide.

Until you upgrade, restarting the service remains the way to clear the stuck groom jobs.

Could you also tell us which version and database type, SQLite, SQL Server or PostgreSQL, your production server uses?

If production already runs 5.5.4 or later, that would explain why it is not affected.

After the upgrade, if "Failed to clear job queue" still appears in the system log, please send us the latest system log and we will look further.

5.5.4 release notes: https://forum.devolutions.net/topics/54570/powershell-universal--554

Upgrade guide: https://docs.devolutions.net/powershell-universal/getting-started/upgrading

Release notes: https://devolutions.net/powershell-universal/release-notes/

Best regards,

Code Folding in VSCode using the Devolutions PowerShell Universal Extension 2026.3.3 is not working.

avatar
avatar
avatar

Hello Finn,

Thank you for the clear description.

We reproduced the issue on our side.

When a script is opened through the PowerShell Universal connection in VS Code, the folding arrows are missing, and Ctrl+K Ctrl+1 does nothing.

The same script folds normally when it is opened from a local folder, which matches what you see.

I have reported it to our development team.

I will let you know as soon as a fix is planned.

Best regards,

Invoke-PSUScript called from an API endpoint ignores scoped script permissions and requires a parent-scope automation permission ("The role specified does not have access to this resource")

avatar
avatar
avatar

Hello Dylan,

Thank you for the detailed report and the test matrix, it made the analysis much faster.

We reproduced the issue in our lab on PowerShell Universal 2026.3.3 on Windows.

Invoke-PSUScript checks your permissions on the script three times: when it looks the script up by name, when it reads the script's parameter list, and when it starts the job.

On Windows, the parameter list check writes the script path with forward slashes, while the other two checks use backslashes.

Your scoped permissions use backslashes, so the parameter list check never matches them for a script in a subfolder.

That is why a parent permission such as automation/read unlocks the call.

Scripts at the root of the Scripts list are not affected, because their path has no folder separator.

I have escalated this to our development team with your test matrix and our reproduction steps.

In the meantime, you can keep the delegation limited to this one script by adding a second Read permission, written with forward slashes, to the role DLG-PSU_2424.

In .universal/roles.ps1, add it to the Permissions list of the DLG-PSU_2424 role, next to automation.scripts/view.

-Permissions @('automation.scripts/view', 'automation.scripts.<Folder>/Add-UserToADGroup/Add-UserToADGroup.ps1/read')

Keep your two existing scoped permissions, because the lookup by name and the job start still need the backslash form.

Please do not recreate them from the script's Permissions dialog, since in 2026.3.3 the dialog saves the forward-slash form, which the other two checks reject.

In our lab, this ran the script from an authenticated endpoint with and without -Wait, with no other permission on the role.

You can remove the extra entry once the fix is installed.

If you prefer not to change the role, two other setups also worked in our lab.

Call Invoke-PSUScript with -AppToken and -ComputerName, using an app token stored as a secret whose role holds automation.scripts/read and an Execute permission in the same backslash form you use today, so your users only need access to the endpoint.

Move Add-UserToADGroup.ps1 to the root of the Scripts list and recreate its Read and Execute permissions on the new path.

App tokens: https://docs.devolutions.net/powershell-universal/security/app-tokens

One detail would help the developers: in test 10, had automation/read already been removed from the role when you added automation/execute?

In our lab, automation/execute alone was still denied, so your answer tells us whether your environment behaves differently.

Best regards,

2026.3.3 - Error when attempting to connect to Terminals

avatar
avatar
avatar

Hello Matt,

Thank you for the clear steps and the full error text.

This is a known issue in PowerShell Universal 2026.3.3.

It happens when a code editor has already loaded in the same browser tab before you connect to the terminal, for example after you open a script or an app.

The editor changes how the page loads scripts, so the small add-on the terminal uses to size itself never registers.

The terminal then cannot start and shows the "fit addon assets failed to initialize" error.

The fix is done and will ship in the next release, 2026.3.4 (ticket PSU-1417, for internal reference only).

Until then, you can avoid the error this way:

Go to Run > Terminals and press F5 to reload the page.

Connect to your terminal before you open any script, app, or other code editor.

If you need an editor and a terminal at the same time, keep a second browser tab only for Terminals.

The same cause was reported for the admin console terminal, and you can follow that thread here: https://forum.devolutions.net/topics/56595/202632--admin-terminal-doesnt-open-on-all-pages

Terminals are documented here: https://docs.devolutions.net/powershell-universal/automation/terminals

If the error still shows right after a fresh F5 on the Terminals page, please tell us which browser you use and whether PowerShell Universal runs behind IIS or a reverse proxy.

Best regards,

MCP Server not producing helpful output

avatar
avatar
avatar
avatar

Hello Matthew Morrow,

I do understand your point, and I have provided a workaround.

As you can see, the thread was moved to the feature request thread yesterday.

I'll let the dev team evaluate your request.

Best regards,

Job history is empty, max history is default (100)

avatar
avatar
avatar
avatar

Hello,

Thank you for the detailed numbers, which confirmed your theory.

Max Job History keeps the newest jobs for each script, and archived jobs count toward that total.

Jobs outside that window are deleted, archived or not.

For your every-minute script, 500 jobs cover only about 8 hours of runs, so you see just the few runs in that window that did work.

We reproduced this on 2026.1.3 and 2026.3.3, so an upgrade will not change it.

As a workaround, set Max Job History to the runs per day times the days you want to keep, for example, 10,080 for 7 days on the every-minute script.

This adds rows to the Job table, so please watch the database size.

The setting is described here: https://docs.devolutions.net/powershell-universal/automation/scripts

We are moving this thread to the PowerShell Universal Feature Request section so our development team can review leaving archived jobs out of the count.

Best regards,

Custom login screen not working post 2026.3 upgrade

avatar
avatar
avatar

Hello Darrell,

Thank you for the clear description and the CSS sample.

The cause is a change in the new 2026.3 login page design.

The login page now sets its own background image on .ant-layout, and that rule also uses !important.

This built-in rule loads after your login stylesheet.

When two rules have the same selector and both use !important, the one that loads last wins.

Your stylesheet still loads, but it is now outranked.

You can get your image back with a more specific selector.

You also need !important on the other background properties, since the built-in rule sets them too.

Please replace your current rule with this one:

html body section.ant-layout,

:root[data-theme="dark"] body section.ant-layout {

background-image: url('/assets/backgroundLogo.jpg') !important;

background-position: center top !important;

background-repeat: no-repeat !important;

background-size: cover !important;

}

The second selector covers the dark theme, which has its own built-in background.

After you save the file, reload the login page with Ctrl+F5 so the browser does not use a cached copy.

We tested this rule against the 2026.3 login page, in both the light and dark themes, and the custom image displays.

If the image still does not show, open the browser developer tools on the login page and check the Network tab.

In a private window, before anyone signs in, both your stylesheet and the image should load with a 200 status.

If either one returns 401 or 404, please tell me how the stylesheet is set, from Settings, Branding or from the branding.ps1 file.

A screenshot of that Network tab would also help.

I will also share this with our development team, so a custom login stylesheet can override the default background again without these extra selectors.

Best regards,

1 - 25 of 970 items