Not sure how to start developing in PSU

Hi guys, I’m a sysadmin, not a developer, so please bare with me here.
With now legacy v2, I used VSCode and “PowerShell UDStudio” extension. I would install and import “UniversalDashboard” module from repo, VSCode would recognize dasboard.ps1 file, import the module and off I go coding… you know the drill.

However, v3 has moved away from these practices and I am not quite sure where to even begin now. Documentation only shows setup steps and debugging section is… well… it makes little to no sense to me at this point lol

At the very least, I would like to be able to somehow attach powershell to my PSU instance and read errors or verbose output. Unlike with dashboards, there appears to be no visual feedback for PSU?

Right now I have local dev (msi) and prod environment (zip+IIS) set up with Azure DevOps pipelines synchronizing repo folder, basic install of PSU is running nicely so far.
First and foremost, I am trying to set up authentication and authorization rules. However I noticed that they are now applied on PSU level and not dashboard level.

So if I want to write scripts for PSU, where do I see script output and errors? Dashboards gets Info/Log/Console tabs, but how do I develop for PSU? Text logs?

One more question - how do I import PSU and Dashboard cmdlets into VSCode? If it’s a manual process now, do I just create new .ps1 file and run it every time I restart VSCode?

Thank you

1 Like

I’ll improve that debugging section. It should have a step-by-step overview of how to debug the various features of PSU.

The dashboard does a good job of logging. If you add the -Debug switch to New-PSUDashboard in dashboards.ps1 of your repo folder you’ll actually get more information out. You can even use Write-Debug to have it show up in the log in the browser.

As for debugging authentication and authorization, we need to hook the PowerShell debugger up to best see what’s going on in there. I really think we need to add a log file for those as well but that’s not there yet.


NOTE: If you are running as the MSI, you probably won’t be able to do this because it’s running as the system account and you won’t have access. You’ll have to stop the service and run the process as your user. Just double-click Universal.Server in your install dir to start it up.

If you want to hook a PowerShell debugger up to PSU, you can do the following.

In your Authentication or Role policy scripts, you can put a Wait-Debugger to cause the script to stall until you connect.

Then, you will want to connect to the PSU process. You can do this using Get-PSHostProcessInfo and looking for the Universal.Server.exe process. Then you can use Enter-PSHostProcess to attach to that process.

Then, you’re going to want to try to login to your PSU instance. This will hang because of the Wait-Debugger command that you put in your scripts.

Within your PowerShell prompt, the one you executed Enter-PSHostProcess, you can now run Get-Runspace and you’ll see that one of the runspaces is InBreakpoint. This is the runspace that is currently sitting on Wait-Debugger.

Now, use Debug-Runspace with that runspace’s ID. And boom, you’ll be in the runspace and you can evauluate variables and run commands etc.

It’s possible to do this in VS Code but what I’ve been finding is that the VS Code PowerShell extension freaks out and I can’t do much once I’m actually attached.

You can also use these common debugging commands to move through your script in the console:

Obviously, we are looking to improve this. I want to get a VS Code extension up and running that allows for debugging stuff easier.

1 Like

I’ve beefed up the docs with this information. Let me know if that’s helpful.

1 Like

This is brilliant, @adam and a lot to process, thank you so much.
I will be going through all you wrote and the updated docs now, should be a lot of fun.
Worst case scenario, if I run into issues attaching debugger, I’ll just append to some external log file that I can then monitor.

Oh, btw on the second question.
Should I just import the UniversalDashboard v2 from packetmanager when working with UD?

Running below only gives me a handful of generic cmdlets:

Import-Module "C:\Program Files (x86)\Universal\Universal.psd1"

The dashboard cmdlets are in C:\ProgramData\PowerShellUniversal\Dashboard\Frameworks

You can import the module from there. I think in v1.3 we’ll have a way to just do this automatically so it isn’t such a pain.

When you import Universal, make sure to do it at the global scope and do import it before the framework.

Import-Module "C:\Program Files (x86)\Universal\Universal.psd1" -Scope Global
1 Like

@adam no joy.
I have updated NTFS permissions, tried running .exe or service as myself or local admin, but all I get is error that has no solution on google.
I get this error with both ZIP/IIS and MSI setups

Basically, as a sysadmin coming from ISE, all I really want is to be able to look at variables in a live session, not even too worried about connecting debuggers. PSU runs some sort of powershell instance/session correct? Can I connect to it from within VSCode when I open the repo?
With v2, I would simply run my dashboard.ps1 file within VSCode and would be able to get/set variables live because it was the same powershell session in VSCode and felt very similar to developing stuff in ISE. This allowed for very rapid development of UD pages.
Taking away this ability is like writing PS scripts in a notepad.exe and running said script to output variable to a text file, feels very backwards lol :smiley:

Sorry if it sounds like I’m complaining, I’m, not. I am just literary lost and can’t find any help online on the subject. The learning curve for UD was already quite steep for sysadmins, but this … I mean it’s been 2-3 days and I got nothing to show for it lol.

So far, I am considering going back to v2 because it enabled rapid development of dashboards, but the API, Automation and dashboard integration under one roof is just too damn tempting to give up just yet.

One potential solution is to use Write-Host in Console and switching to Log tab to see the ouput. But this is very clunky, requires a lot of scrolling, outputs are refreshed on every click and overall feels so wrong and backwards that it defeats the whole purpose of using VSCode with integrated PS console.

Console also appears to be locked onto system32 (MSI) or PSU core file directory (ZIP) and not dashboard repository, which I find quite confusing. Using Set-Location (CD) has no effect.


What do?
Too early to switch over yet?

$PSScriptRoot appears to be $null in both MSI and IIS versions. I must be missing something…

Trying to run v3 example from github and line 215 fails because of this.


If I remove lines 215-218, dashboard works fine, albeit with a ton of 404’s ofcourse

Man, I am literary hitting dead end after dead end here.

Is it possible to ditch the PSU infrastructure and run v3 dashboards standalone from VSCode just like we used to run UD v2? At least for local development, I could then run PSU on IIS on production server.

The Enter-PSHostProcess command is supposed to let you hook up the terminal or VS Code to the PSU process running Universal so if you can’t connect you won’t be able to check out variables in VS Code. The terminal isn’t returning $PSScriptRoot because it runs that command one off and not in a script.

As for the your comment on being able to run UD outside of PSU, we are working on a way to run the PowerShell side of things in VS Code to enable some of the UDStudio features similar to how we had it before. This probably won’t be out for a bit.

I think we should jump on a Zoom call though because I’d like to see what’s going on in your environment. UD and PSU seem pretty unhappy.

Here’s a teaser of some of the new tooling that will be available to host PSU in a separate PS process.

We’ve added some cmdlets to allow you to start up PowerShell and then connect it to PSU. It will load the dashboard and the modules into your PS session.

You’ll see that I can start the dashboard and then get endpoints via Get-PSUDashboardEndpointRunspace and then pass that to Debug-Runspace. Then I can use cmdlets like Get-Variable to check the state of variables.

PS C:\Users\adamr> Import-Module 'C:\\src\\universal\\src\\output\\Cmdlets\\Universal.psd1'
PS C:\Users\adamr> connect-uaserver -computername http://localhost:5000 -AppToken eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiQWR
PS C:\Users\adamr> Connect-PSUDashboard -Id 1
INF: Loading module: C:\program files\powershell\7\Modules\Microsoft.PowerShell.Management\Microsoft.PowerShell.Management.psd1
INF: Loading module: C:\Users\adamr\Documents\PowerShell\Modules\PSReadline\2.1.0\PSReadline.psd1
INF: Loading module: C:\src\universal\src\output\Cmdlets\Universal.psd1
PS C:\Users\adamr> Get-PSUDashboardEndpointRunspace -Id 'page1' | Debug-Runspace
ERR: PS: One or more errors occurred. (Cannot overwrite variable null because it is read-only or constant.) (Cannot overwrite variable null because it is read-only or constant.)
Debugging Runspace: page1
To end the debugging session type the 'Detach' command at the debugger prompt, or type 'Ctrl+C' otherwise.

Entering debug mode. Use h or ? for help.

At line:3 char:1
+ Wait-Debugger
+ ~~~~~~~~~~~~~
[DBG]: [Process:20160]: [page1]: PS C:\Users\adamr>> get-variable

Name                           Value
----                           -----
$                              PS $($executionContext.SessionState.Path.CurrentLocation)>
?                              True
^                              [DBG]:
args                           {}
ConfirmPreference              High
ConnectionId                   Rqgjf3Y3xh6wgjgLoxQlAQ
DashboardHub                   UniversalDashboard.DashboardHubProxy
DashboardService               UniversalDashboard.Services.DashboardService
DebugPreference                SilentlyContinue
EnabledExperimentalFeatures    {}
Endpoint                       UniversalDashboard.Models.Endpoint
EndpointService                UniversalDashboard.Execution.EndpointService
Error                          {}
ErrorActionPreference          Continue
ErrorView                      ConciseView
EventId                        page1
ExecutionContext               System.Management.Automation.EngineIntrinsics
false                          False
FormatEnumerationLimit         4
HOME                           C:\Users\adamr
Host                           System.Management.Automation.Internal.Host.InternalHost
InformationPreference          SilentlyContinue
IsCoreCLR                      True
IsLinux                        False
IsMacOS                        False
IsWindows                      True
MaximumHistoryCount            4096
MyInvocation                   System.Management.Automation.InvocationInfo
NestedPromptLevel              0
OutputEncoding                 System.Text.UTF8Encoding
page                           {id, defaultHomePage, url, content…}
PID                            20160
PROFILE                        C:\Users\adamr\Documents\PowerShell\Microsoft.PowerShell_profile.ps1
ProgressPreference             Continue
PSBoundParameters              {}
PSCulture                      en-CH
PSDebugContext                 System.Management.Automation.PSDebugContext
PSDefaultParameterValues       {}
PSEdition                      Core
PSHOME                         C:\Program Files\PowerShell\7
PSSessionApplicationName       wsman
PSSessionOption                System.Management.Automation.Remoting.PSSessionOption
PSUICulture                    en-US
PSVersionTable                 {PSVersion, PSEdition, GitCommitId, OS…}
PWD                            C:\Users\adamr
Roles                          {}
Session                        UniversalDashboard.Models.SessionState
SessionId                      10116715-b958-4b3a-b687-6558e636b18c
ShellId                        Microsoft.PowerShell
StateRequestService            UniversalDashboard.Services.StateRequestService
true                           True
UDConnectionManager            UniversalDashboard.Services.ConnectionManager
UDExecutionService             UniversalDashboard.Execution.PowerShellExecutionService
user                           Admin
VerbosePreference              SilentlyContinue
WarningPreference              Continue
WhatIfPreference               False

[DBG]: [Process:20160]: [page1]: PS C:\Users\adamr>>

In the admin console, the dashboard will be set to debugging.

Additionally, we’ll be releasing a VS Code extension to help make this possible with less typing. There is currently a bug in the PowerShell extension for VS Code that is preventing this from working 100% but once that is fixed you’ll be able to just jump into the debugger in Code.

1 Like

Absolutely, I’m down for zoom/discord/Teams remote session, whichever fits you best. How do we proceed with that?

Some things I have noticed so far are:

  • module related errors when launching Universal.Server.exe, but PSU recovers and works fine after that

  • $PSScriptRoot only works with UD v2.9 framework. It is returned as $null on UD v.3.0

Code I am using:

New-UDDashboard -Title "Hello, World!" -Content {
    New-UDHeading -Text "Script root :: $($PSScriptRoot)"
    Write-Host "Test"

V2 dashboard:

V3 dashboard:

I get same exact result on:
1.2.4, ZIP install for IIS 10.0, application pool is a domain user
1.2.5, MSI install, running as either local system or domain user

As for Enter-PSHostProcess I think I will just uninstall MSI version completely. Then I will set up a PowerShell folder in root drive on C: or D: drive, give if full NTFS access to my user, extract ZIP version, adjust appsettings.json and run PSU manually. So if it was NTFS issue, that should resolve that. This one I feel like I can crack on my own, and it really helps a ton hearing from you that it’s the correct cmdlet I was asking for.