Having tons of trouble hosting in IIS

I don’t remember this being this difficult before, but it’s been a while. I’m getting tons of errors trying to run my dashboard from IIS. Below is my setup, and under that, the error I’m getting.

environment:
Windows 10 Pro, v 1909
IIS 10
UniversalDashboard.Community v 2.9.0
dotnetcore hosting bundle, installed from the link at the top of the UD docs page for IIS

iis folder c:\inetpub\wwwroot

Web.Config (c:\inetpub\wwwroot\web.config)

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <!--
    Configure your application settings in appsettings.json. Learn more at http://go.microsoft.com/fwlink/?LinkId=786380
  -->
  <system.webServer>
    <security>
      <!-- <requestFiltering removeServerHeader ="true" /> -->
    </security>
    <handlers>
      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
    </handlers>
    <aspNetCore processPath="C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" arguments=".\dashboard.ps1" />
    <httpProtocol>
      <customHeaders>
        <remove name="X-Powered-By" />
      </customHeaders>
    </httpProtocol>  
  </system.webServer>
</configuration>

When I start it, here is the error i get:

image

Windows Event viewer gives this error:

failed to start process with commandline 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe .\dashboard.ps1', ErrorCode = '0x80004005' : 0.

That error corresponds to a missing file, but i have no idea which file, and there’s nothing that shows me that i can find.

Are you importing the module at the top of your dashboard.ps1?

Import-Module "$PSScriptRoot\UniversalDashboard.Community.psd1"

What happens when you run powershell.exe manually and start that dashboard?

1 Like

Wow, simply adding the import-module worked!!

Two things - in production, i will be using the enterprise edition, so i assume i will not need this step?

Also, is this requirement a result of changing the web.config from 2.8 > 2.9?

edit: If this is a universal requirement for community, might be worth mentioning it in the docs for IIS, unless i missed it somewhere :slight_smile:

You will need that step for enterprise if you deploy the module into the IIS directory. It’s also possible to install the module to the PSModulePath and then the web.config can just load it from there and module autoloading will kick in and you won’t need to do it manually.

The main difference here is that we just removed the UD.Server.exe because all it was really doing was loading the UD module. So yeah, it’s a difference since 2.9.

And the docs could be more clear on this. They suggest using PSModulePath but not why to do so nor the need to call Import-module manually if not used.

1 Like

Do you have an example of how the second option might look? I would much prefer to have module autoloading if i can get it, since i’m using UniversalDashboard.UDStyle as well, and i can’t get it working.

I understand it as:

  1. Deploy your dashboard.ps1 and code to the IIS folder (c:\inetpub\wwwroot for example)
  2. Install-Module UniversalDashboard.Community
  3. copy included web.config to the root of the IIS site, and edit it to use PSModulePath somehow?

Sorry if i’m being a pest today, getting close to prod here, and i just wanna have all my ducks in a row for that time.

My IIS sites are pretty bare.

image

Then I have a custom identity setup for the AppPool. You’ll need to install the module to somewhere that user can read from. The default AppPool user cannot read outside of the site’s directory so you may need to add a custom user to the permissions of the folder you choose to install to.

Then I set the PSModulePath environment variable for either the user or the machine to point to the install directory. If you use Install-Module, that path will already be there and you’ll like just need to make sure your AppPool user has read permissions to that folder.

As @adam already described, the easiest way is to install the UniversalDashboard module for the user that is running your apppool.
Let’s call him uduser for now.
Then you log in with user uduser per RDP OR open a powershell window as different user (uduser) and install the UniversalDashboard Module with install-module UniversalDashboard.Community -AcceptLicense -Confirm:$false -Scope CurrentUser -Verbose.

After that you can copy over the included web.config to your iis or a custom web.config as, f.e. described here. After that you do not need to import the UniversalDashboard.Community module because it will be automatically imported.

Also make sure to specify the -Wait parameter in Start-UDDashboard, you will also get an 502.5 Internal Server Error if the switch was not given.

Keep in mind: If you are using the Cache Scope ($Cache:…) in your dashboard.ps1 BEFORE using any UD cmdlet (so the module is not imported) you will get errors. Then you need to import the module first or one of the UD cmdlets first.

EDIT:

My best way to identify IIS + UD problems is to activate the logging in the web.config to a folder inside your website location (so you have easy access to it). You could also integrate a small html5 log viewer and view the logs inside the browser (@adam Could be a possible integration into UD (Admin Page) in the future ;-)?)

Example:

<aspNetCore processPath="C:\Program Files\PowerShell\7\pwsh.exe" arguments=".\dashboard.ps1" stdoutLogEnabled="true" stdoutLogFile=".\logs\\stdout" forwardWindowsAuthToken="true" requestTimeout="09:00:00" />

If your web.config is located in C:\inetpub\wwwroot\web.config the logs folder with the stdout file is then located in C:\inetpub\wwwroot\logs\stdout. Everything ud will log during startup of IIS (stdout) will be logged to this file (also some information that the UD internal logging will not show up). The file name will also include the process id and current startup date. -Wait is a Requirement for that to work.

Example:


image

The default location for the stdout logfile is stdoutLogFile="\\?\%home%\LogFiles\stdout". %home% is your user home directory. So if your user is called uduser it’s located in C:\users\uduser\LogFiles\stdout.

2 Likes

Thanks, this is super detailed, i’m gonna give this a try later.

1 Like

@Mordecai I am making progress for sure- the logging was a HUGE help, thank you!. so my dashboard.ps1 is now failing saying New-UDRow is not recognized as the name…etc. Adam mentioned above

It’s also possible to install the module to the PSModulePath and then the web.config can just load it from there and module autoloading will kick in and you won’t need to do it manually.

Every module i need is installed under -CurrentUser <name_of_my_dashboard_user> context, so
How would i tell my web.config to ‘load it from there’ so i can get module autoloading?

I would think if the universaldashboard.community module is installed under the context of the user running the app pool, it’s already in a valid $env:PSModulePath path (C:\Users<username>\Documents\WindowsPowerShell\Modules) so it should just work, but it’s not loading it for me.

I added a logging line to spit out the current user and the psmodule path - it’s the correct user, but psmodule path is only listing the system one, not the user one.

This is a domain account, if that makes a difference.

Edit: I was able to get module auto-loading working if i manually appended to PSModulePath and specified a location that my user has access to:

at the top of dashboard.ps1:

$Env:PSModulePath = $Env:PSModulePath + ";C:\PSModules"

Glad I could help you.
I just remembered a mistake that happened to me. Did you set the IIS AppPool to load the user’s profile? Then the users profile will be loaded on app pool startup (This includes their cryptographic store, environment variables such as %TEMP%, PSModulePath and other ones.)

Go the advanced settings of your apppool and check if LoadUserProfile is set to $true.

Keep in Mind: When Load User Profile is true, the %TEMP% environment variable is C:\Users\AccountName\AppData\Local\Temp (for example). When false, it’s C:\WINDOWS\Temp. Make sure to change the variable if you are using $env:Temp, %TEMP% etc.

You can find more information in the processmodel documentation. Look for “LoadUserProfile”.

2 Likes