Powershell scripting creation of a "sub" website - asp.net

I have two folders:
c:\inetpub\site1
c:\inetpub\site1Sub
I want "site1" to be the "parent" website and "site1Sub" to be a "sub" website. Both sites should run under the same application pool, which is a custom pool created solely for these sites, call it "site1." In IIS Manager (7.5), I simply create the application pool, then the parent site, then right-click on the parent site and "Add Application," pointing it at the physical path "c:\inetpub\site1Sub." This all works fine.
When I try to script this in Powershell, however, things get difficult. I can create "site1" and the application pool with no problems. It's the sub-site that's being a pain. I've tried two approaches:
Approach 1: Use New-Item and set the app pool after.
$subSite = New-Item "IIS:\Sites\site1\site1Sub" -physicalPath "C:\inetpub\site1Sub" -type "Application"
$subSite | Set-ItemProperty -Name "applicationPool" -Value "site1"
With this approach, I receive an error after the Set-ItemProperty command:
Set-ItemProperty : Cannot find path 'C:\site1Sub' because it does not exist.
At line:1 char:127
+ $subSite | Set-ItemProperty -Name "applicationPool" -Value "site1" ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\site1Sub:String) [Set-ItemProperty], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.SetItemPropertyCommand
Approach 2: Create a virtual directory and use ConvertTo-WebApplication (as in this answer).
New-WebVirtualDirectory -Site "site1" -Name "site1Sub" -PhysicalPath "c:\inetpub\site1Sub"
ConvertTo-WebApplication -ApplicationPool "site1" "IIS:\Sites\site1\site1Sub"
This runs fine, and further, it looks fine in IIS Manager, but when I attempt to navigate to the site I receive an error stating that the web.config failed to parse:
It is an error to use a section registered as
allowDefinition='MachineToApplication' beyond application level. This
error can be caused by a virtual directory not being configured as an
application in IIS.
I'm totally stumped. How can I script this scenario in Powershell?

I've found that when creating an application under a website, I've needed to specify the -Force switch in the call to New-Item. I've left out the checking to see if the site already exists (Sneijder's answer shows how to do that with Test-Path), but this should do the trick:
Import-Module WebAdministration
$sitePath = 'IIS:\Sites\site1'
$subSitePath = "$sitePath\site1Sub"
$appPoolName = 'site1'
# Create Site and Subsite
New-Item $sitePath -PhysicalPath 'C:\Inetpub\site1' -Bindings #{protocol="http";bindingInformation=":80:"} }
New-Item $subSitePath -Type Application -PhysicalPath 'C:\Inetpub\site1Sub' -Force
# Create App Pool
New-Item "IIS:\AppPools\$appPoolName"
# Associate sites to App Pool
Set-ItemProperty $sitePath -Name applicationPool -Value $appPoolName
Set-ItemProperty $subSitePath -Name applicationPool -Value $appPoolName

As i understand you correctly, you would like to have following result in your local IIS Manager:
This script creates an application pool. Then it creates the root site and afterwards the subsite.
Import-Module WebAdministration
$iisAppPoolName = "applicationPool"
$iisAppPoolDotNetVersion = "v4.0"
$iisAppName = "site1"
$directoryPath = "C:\inetpub\site1"
$iisSubAppName = "site1sub"
$directorySubPath = "C:\inetpub\site1Sub"
#navigate to the app pools root
cd IIS:\AppPools\
#check if the app pool exists
if (!(Test-Path $iisAppPoolName -pathType container))
{
#create the app pool
$appPool = New-Item $iisAppPoolName
$appPool | Set-ItemProperty -Name "managedRuntimeVersion" -Value $iisAppPoolDotNetVersion
}
#navigate to the sites root
cd IIS:\Sites\
#check if the site exists
if (Test-Path $iisAppName -pathType container)
{
return
}
#create the site
$iisApp = New-Item $iisAppName -bindings #{protocol="http";bindingInformation=":80:"} -physicalPath $directoryPath
$iisApp | Set-ItemProperty -Name $iisAppPoolName -Value $iisAppPoolName
#create the subSite
$iisSubApp = New-WebApplication -Name $iisSubAppName -Site $iisAppName -PhysicalPath $directorySubPath -ApplicationPool $iisAppPoolName
Result:
Hope this helps.

Have you tried mapping your IIS directory tree as a PSDrive, then re-attempt approach 1?
https://technet.microsoft.com/en-us/library/ee176915.aspx
Do a Get-PSDrive to see what PS Providers are available to the host, then attempt to map it like a filesystem.
# For psprovider, I'm not sure if the provider name is 'IIS' or some other.
# For mapping remote drives, usually FileSystem works,
# but try Get-PSDrive to see whats available to your host for this switch.
New-PSDrive -name X -psprovider IIS -root 'IIS:\'
I don't have IIS config'd on my testbox to confirm for you, but just putting this up here to try.

Related

Unable to run docker IIS windows container

I am new to docker and trying to run legacy .NET applications inside a windows container (using docker desktop). Here is my dockerfile
FROM mcr.microsoft.com/windows/servercore:ltsc2019
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop';"]
RUN dism.exe /online /enable-feature /all /featurename:iis-webserver /NoRestart
#Configure IIS
RUN Import-Module WebAdministration;New-Item –Path IIS:\AppPools\CustomApppool
RUN C:\windows\system32\inetsrv\appcmd.exe set apppool /apppool.name:CustomApppool /processModel.identityType:SpecificUser /processModel.username:us\user1 /processModel.password:P##Ss
RUN Install-WindowsFeature Web-Windows-Auth;
RUN Install-WindowsFeature Web-IP-Security;
RUN Install-WindowsFeature NET-WCF-HTTP-Activation45;
RUN Install-WindowsFeature Web-Dyn-Compression;
RUN Install-WindowsFeature Web-Scripting-Tools;
RUN Install-WindowsFeature Web-AppInit;
RUN Install-WindowsFeature Web-Http-Redirect;
RUN Install-WindowsFeature Web-WebSockets;
# Update permissions on website folder
RUN icacls 'c:\inetpub\wwwroot' /Grant 'IUSR:(OI)(CI)(RX)'
RUN icacls 'c:\inetpub\wwwroot' /Grant 'IIS AppPool\DefaultAppPool:(OI)(CI)(RX)'
RUN icacls 'c:\inetpub\wwwroot' /Grant 'IIS AppPool\CustomApppool:(OI)(CI)(RX)'
#Copy website files from App host folder to container wwwroot folder
COPY Admin/ "c:/inetpub/wwwroot/Admin"
COPY Sade/ "c:/inetpub/wwwroot/Sade"
COPY Rater/ "c:/inetpub/wwwroot/Rater"
#Copy Service Monitor file
COPY ServiceMonitor.exe C:/
RUN New-WebApplication -Name Admin -Site 'Default Web Site' -PhysicalPath C:\inetpub\wwwroot\Admin -ApplicationPool CustomApppool;
RUN New-WebApplication -Name Sade -Site 'Default Web Site' -PhysicalPath C:\inetpub\wwwroot\Sade -ApplicationPool CustomApppool;
RUN New-WebApplication -Name Rater -Site 'Default Web Site' -PhysicalPath C:\inetpub\wwwroot\Rater -ApplicationPool CustomApppool;
#Authentication Settings
# Enable Directory browsing
RUN C:\Windows\system32\inetsrv\appcmd.exe set config 'Default Web Site' /section:system.webServer/directoryBrowse /enabled:'True'
# Enable anonymous authentication
RUN Set-WebConfigurationProperty -Filter '/system.webServer/security/authentication/anonymousAuthentication' -Location 'Default Web Site' -Name enabled -Value True;
# Enable basic authentication
#RUN Set-WebConfigurationProperty -Filter '/system.webServer/security/authentication/basicAuthentication' -Location 'Default Web Site' -Name enabled -Value True;
# Enable Windows authentication
RUN Set-WebConfigurationProperty -Filter '/system.webServer/security/authentication/windowsAuthentication' -Location 'Default Web Site' -Name Enabled -Value False;
RUN Restart-Service W3SVC
EXPOSE 80
ENTRYPOINT ['C:\ServiceMonitor.exe','w3svc']
I am able to build the image by running docker build -t demo/site
I am running this command to start the container docker run -p 8000:80 demo/site:latest but i am getting this error:
At line:1 char:35
+ $ErrorActionPreference = 'Stop'; ['C:\ServiceMonitor.exe','w3svc']
+ ~
Missing type name after '['.
At line:1 char:58
+ $ErrorActionPreference = 'Stop'; ['C:\ServiceMonitor.exe','w3svc']
+ ~
Missing argument in parameter list.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordEx
ception
+ FullyQualifiedErrorId : MissingTypename
Please, what am i missing? What do i need to do to get the container to start, and to be able to browse my website on localhost?
Replace your single quotes on the last line with double quotes.
Also try replacing ENTRYPOINT with CMD as well.

Running ASP.NET 4.6 application inside a docker container - Site always 404s

I've been attempting to get an ASP.NET 4.6 application to run inside a Windows Docker container and while getting IIS to run with the default website was fairly simple, trying to get my actual application to run is proving to be difficult. Whenever I attempt to load my application it returns a 404 file not found.
Some background: The application I'm trying to run has to be installed under 'Default Web Site' with both the application and a SharedContent application installed under IIS, where the SharedContent is also a sub-application under the main application.
This results in 3 calls install the application under IIS:
RUN ["powershell", "New-WebApplication -Name MvcCompaniesV2 -Site 'Default Web Site' -PhysicalPath C:/inetpub/wwwroot/MvcCompaniesV2 -ApplicationPool DefaultAppPool"]
RUN ["powershell", "New-WebApplication -Name SharedContent -Site 'Default Web Site' -PhysicalPath C:/inetpub/wwwroot/SharedContent -ApplicationPool DefaultAppPool"]
RUN ["powershell", "New-WebApplication -Name MvcCompaniesV2/SharedContent -Site 'Default Web Site' -PhysicalPath C:/inetpub/wwwroot/SharedContent -ApplicationPool DefaultAppPool"]
After fiddling around for about a full day I'm confused. I managed to install IIS WebManagement and can connect to my container using the IIS Manager and I can see my websites are properly configured with one exception: the connection strings and rewrite rules from the web.config aren't visible from the IIS settings, like it can't access the config file. IIS runs under the IIS APPPOOL\DefaultAppPool user and the wwwroot folder has IIS_IUSRS added to its ACL(as by default).
This is my docker file:
FROM microsoft/aspnet:4.7.2-windowsservercore-1803
EXPOSE 80
EXPOSE 8172
EXPOSE 4020 4021 4022 4023
# WebManagement stuff
RUN ["powershell.exe", "Install-WindowsFeature NET-Framework-45-ASPNET"]
RUN ["powershell.exe", "Install-WindowsFeature Web-Asp-Net45"]
RUN ["powershell.exe", "Install-WindowsFeature web-mgmt-service"]
RUN ["powershell.exe", "Set-ItemProperty -Path 'HKLM:/SOFTWARE/Microsoft/WebManagement/Server' -Name 'EnableRemoteManagement' -Value 1"]
RUN ["powershell.exe", "set-service -Name WMSVC -StartupType Automatic"]
RUN ["powershell", "start-service WMSVC"]
RUN ["powershell", "net user patrick l0lp#ssw0rd /add"]
RUN ["powershell", "net localgroup administrators patrick /add"]
# Rewrite module
ADD https://download.microsoft.com/download/C/9/E/C9E8180D-4E51-40A6-A9BF-776990D8BCA9/rewrite_amd64.msi rewrite_amd64.msi
RUN ["powershell" , "Start-Process msiexec.exe -ArgumentList '/i', 'rewrite_amd64.msi', '/quiet', '/norestart' -NoNewWindow -Wait"]
# Remote debugger
RUN Invoke-WebRequest -OutFile c:\rtools_setup_x64.exe -Uri https://aka.ms/vs/15/release/RemoteTools.amd64ret.enu.exe;
RUN & 'c:\rtools_setup_x64.exe' /install /quiet
ADD bin C:/inetpub/wwwroot/
RUN ["powershell", "New-WebApplication -Name MvcCompaniesV2 -Site 'Default Web Site' -PhysicalPath C:/inetpub/wwwroot/MvcCompaniesV2 -ApplicationPool DefaultAppPool"]
RUN ["powershell", "New-WebApplication -Name SharedContent -Site 'Default Web Site' -PhysicalPath C:/inetpub/wwwroot/SharedContent -ApplicationPool DefaultAppPool"]
RUN ["powershell", "New-WebApplication -Name MvcCompaniesV2/SharedContent -Site 'Default Web Site' -PhysicalPath C:/inetpub/wwwroot/SharedContent -ApplicationPool DefaultAppPool"]
# ErrorPages mode to off
RUN ["powershell", "Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT' -filter 'system.web/customErrors' -name 'mode' -value 'Off'"]
RUN ["powershell", "Set-WebConfigurationProperty -filter 'system.webServer/httpErrors' -name 'errorMode' -value 'Detailed'"]
RUN ["Powershell", "Set-WebConfigurationProperty -pspath 'IIS:\Sites\Default Web Site\MvcCompaniesV2' -filter 'system.webServer/httpErrors' -name 'errorMode' -value 'Detailed'"]
ENTRYPOINT ["powershell", ""]
Any ideas on how I can troubleshoot this? As can be seen, I changed the errorPages mode for both IIS and .NET to detailed but whenever I open MvcCompaniesV2, I still get the very limited error page (https://imgur.com/a/jvj9r7f). I'm kind of out of ideas what I can try to troubleshoot this.
I tried a sample asp.net page(which runs directly under 'Default Web Site' and that works fine out of the box').
EDIT: When I attach the remote debugger to my project it breaks with an ArgumentException inside the framework code:
System.ArgumentException
HResult=0x80070057
Message=The parameter 'C:/inetpub/wwwroot/MvcCompaniesV2\' is invalid.
Parameter name: C:/inetpub/wwwroot/MvcCompaniesV2\
I fixed this problem by fixing the malformed 'PhysicalPath's from the New-WebApplication calls. The debugger's ArgumentException gave it away, IIS doesn't tolerate / in the paths. After updating them to C:\\inetpub\\wwwroot\\MvcCompaniesV2 the problem went away.

Disable UAC, restart and install programs

I tried to disable UAC, restart the machine and install the program. I found an article how can create workflow, but it not works for me. When I run it once, the computer restarts, UAC is still enabled, and nothing happen.
workflow Resume_Workflow
{
Set-ItemProperty -Path REGISTRY::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System -Name ConsentPromptBehaviorAdmin -Value 0
Restart-Computer -Wait
Start-Process msiexec.exe -Verb runAs -PassThru -Wait -ArgumentList '/I C:\tmp\_deployment\tightvnc-2.8.11-gpl-setup-64bit.msi /quiet /norestart'
}
# Create the scheduled job properties
$options = New-ScheduledJobOption -RunElevated
$AtStartup = New-JobTrigger -AtStartup
# Register the scheduled job
Register-ScheduledJob -Name Resume_Workflow_Job -Trigger $AtStartup -ScriptBlock ({[System.Management.Automation.Remoting.PSSessionConfigurationData]::IsServerManager = $true; Import-Module PSWorkflow; Resume-Job -Name new_resume_workflow_job -Wait}) -ScheduledJobOption $options
# Execute the workflow as a new job
Resume_Workflow -AsJob -JobName new_resume_workflow_job
Any idea what's missing?
Thanks for the help.

IIS:\\AppPools appears to be empty when used from inside application pool

I am trying to run a PowerShell script to set some properties on an IIS application pool. The script works fine when I run it from the PowerShell application. However, it does not work when running from inside an IIS application pool.
The script looks as follows:
import-module webadministration
$WebSiteName = "MyWebsite"
$WebSiteFullName = "IIS:\Sites\" + $WebSiteName
$ApplicationPool = Get-Item $WebSiteFullName | Select-Object applicationPool
$ApplicationPoolFullName = "IIS:\AppPools\" + $ApplicationPool.applicationPool
Add-WebConfiguration -filter '/system.applicationHost/serviceAutoStartProviders' -value (#{name="ApplicationPreload";type="MyApplication.ApplicationPreload, MyApplication"})
set-itemproperty $WebSiteFullName -name applicationDefaults.serviceAutoStartEnabled -value True
set-itemproperty $WebSiteFullName -name applicationDefaults.serviceAutoStartProvider -value 'ApplicationPreload'
set-itemproperty $ApplicationPoolFullName -name autoStart -value True
set-itemproperty $ApplicationPoolFullName -name startMode -value 1 # 1 = AlwaysRunning
Its purpose is to make an ASP.NET application using Hangfire always running, as described here: http://docs.hangfire.io/en/latest/deployment-to-production/making-aspnet-app-always-running.html
The script runs fine when run in the PowerShell application.
However, when it from the ASP.NET application using System.Management.Automation, the last two lines fail. The error message is:
Cannot find path 'IIS:\\AppPools\\fwsetupsite' because it does not exist.
As a test, I added a line
dir IIS:\AppPools > c:\apppools.txt
which produces an empty file c:\apppools.txt if run from the ASP.NET application, but correctly dumps the names of all application pools into the file when run from the PowerShell application. So it seems that IIS:\\AppPools is empty.
The C# code which runs the script from within the ASP.NET application looks as follows:
using (PowerShell shell = PowerShell.Create())
{
string script = File.ReadAllText(FilePath);
shell.AddScript(script);
shell.Invoke();
}
It seems that making the modifications to the application pool in a background job solves the problem:
$job = Start-Job -ScriptBlock {
param($ApplicationPoolFullName)
import-module webadministration
# Enable auto start and always running on application pool
set-itemproperty $ApplicationPoolFullName -name autoStart -value True
set-itemproperty $ApplicationPoolFullName -name startMode -value 1 # 1 = AlwaysRunning, 0 = OnDemand
} -ArgumentList $ApplicationPoolFullName
Wait-Job $job | Out-Null
if ($job.State -eq 'Failed') {
exit 1
}
I am still curious about why it doesn't work when doing it directly in the main script, though.

500 error when uploading an image from iOS to IIS post webservice

I'm trying to upload a file to an IIS 8 server from my .NET website. When I upload it from the desktop, everything works fine and the webservice returns success. When I try to upload the image through my iPhone iOS, I gt a 500 internal server error. Is there any way to detect the exact internal exception from the log, because I could'nt find anything specific, just a 500 for the webservice all.I have the option to put console.log() and get information from the client side, but it doesn't help me to detect the problem. I can't debug it as usually because I browse the site through a mobile phone.
Turn on Failed Request Tracing in IIS, you can use the GUI or PowerShell like this:
$siteName = "name of your web site"
Enable-WindowsOptionalFeature -Online -FeatureName IIS-HttpTracing
Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -filter "system.applicationHost/sites/site[#name=`'$siteName`']/traceFailedRequestsLogging" -name "enabled" -value "True"
Add-WebConfigurationProperty -pspath "MACHINE/WEBROOT/APPHOST/$siteName" -filter "system.webServer/tracing/traceFailedRequests" -name "." -value #{path='*'}
Add-WebConfigurationProperty -pspath "MACHINE/WEBROOT/APPHOST/$siteName" -filter "system.webServer/tracing/traceFailedRequests/add[#path='*']/traceAreas" -name "." -value #{provider='ASPNET';areas='Infrastructure,Module,Page,AppServices';verbosity='Verbose'}
Set-WebConfigurationProperty -pspath "MACHINE/WEBROOT/APPHOST/$siteName" -filter "system.webServer/tracing/traceFailedRequests/add[#path='*']/failureDefinitions" -name "statusCodes" -value "500"
Add-WebConfigurationProperty -pspath "MACHINE/WEBROOT/APPHOST/$siteName" -filter "system.webServer/tracing/traceFailedRequests/add[#path='*']/traceAreas" -name "." -value #{provider='WWW Server';areas='Authentication,Security,Filter,StaticFile,CGI,Compression,Cache,RequestNotifications,Module,WebSocket';verbosity='Verbose'}
after that run your failing requests and check the log files under C:\inetpub\logs\FailedReqLogFiles\
it is easier to copy the files to your workstation and open them in IE

Resources