Quantcast
Channel: Jeong's Blog
Viewing all 23 articles
Browse latest View live

IIS Powershell User guide - Comparing representative IIS UI tasks

$
0
0

1.    [File System] Open Explorer window for Default Web Site's home directory

 

$path = $(get-item 'iis:\sites\default web site').physicalPath

$path = [system.environment]::ExpandEnvironmentVariables($path)

explorer $path

 Related UI Task:"Explorer" 

 

2.    [File System] Open Explorer window for Default Web Site's home directory using "DirectoryName" property

 

$path = $(get-item 'iis:\sites\default web site\iisstart.htm').directoryName

explorer $path

 Related UI Task:"Explorer" 

 

3.    [File System] Create File and set file content programmatically

 

$file = new-item demo.htm -type file

set-content $file.FullName "Hey, dude!"

 Related UI Task:"Explorer" 

 

4.    [File System] Set "Deny" for administrator user account for 'iisstart.htm' file and grant access permission for NTAccount

 

$file = $(get-item "iis:\sites\Default Web Site\iisstart.htm ")

$dacl = $file.GetAccessControl()

$newRule = New-Object Security.AccessControl.FileSystemAccessRule Administrator, Modify, Deny

$modified = $false

$dacl.ModifyAccessRule("Add", $newRule, [ref]$modified)

$file.SetAccessControl($dacl)

$file.GetAccessControl().GetAccessRules($true, $true, [System.Security.Principal.NTAccount])

 Related UI Task:"Edit Permissions..." 

 

5.    [Application Pool] Get the list of application pools

 
dir iis:\apppools
 Related UI Task:"Application Pools" treeview 

 

6.    [Application Pool] Create a new pool

 

New-Item iis:\apppools\demoAppPool

 Or, you can use other task-based  cmdlet(s) instead: 
New-AppPool demoAppPool
 

NOTE: New-AppPool cannot use full path name such as “iis:\appPools\demoAppPool” like other user-friendly-named cmdlets

 Related UI Task:"Add Application Pool..." 

 

7.    [Application Pool] Rename an Application Pool

 
Rename-Item iis:\apppools\defaultapppool newAppPoolName
 Related UI Task:"Rename " 

 

8.    [Application Pool] Remove an Application Pool

 

Remove-Item iis:\apppools\defaultapppool

 Or, you can use other task-based  cmdlet(s) instead: 
Remove-AppPool defaultapppool
 Related UI Task:"Remove " 

 

9.    [Application Pool] Stop/Start/Recycle Application Pool

 
Start-WebItem IIS:\AppPools\DefaultAppPoolStop-WebItem IIS:\AppPools\DefaultAppPoolRestart-WebItem IIS:\AppPools\DefaultAppPool
 Or, you can use other task-based  cmdlet(s) instead: 

Start-AppPool DefaultAppPool

Stop-AppPool DefaultAppPool

Restart-AppPool DefaultAppPool

 Related UI Task:"Stop/Start/Recycle" 

 

10.[Application Pool] Get the current status of Application Pool

 

Get-WebItemState iis:\apppools\defaultapppool

 Or, you can use other task-based  cmdlet(s) instead: 

Get-AppPoolState defaultapppool

 Related UI Task:"Stop/Start/Recycle" 

 

11.[Application Pool] Get the list of application which is belonged to an Application Pool

 

function ConvertFrom-ItemXPath($itemXpath)

{

    $result = new-object psobject

 

    $tempString = $itemXPath.substring($itemXPath.IndexOf("@name"))   

    add-member -in $result noteproperty Site $tempString.Split("'")[1]

 

    $tempString = $itemXPath.substring($itemXPath.IndexOf("@path"))

    add-member -in $result noteproperty Application $tempString.Split("'")[1]

    return $result

}

 

$applications = get-webconfiguration //application[@applicationPool]

$applications | select itemXpath, applicationpool | foreach {if ($_.applicationPool -eq "DefaultAppPool") {ConvertFrom-ItemXPath ($_.itemXpath)}}

 Related UI Task:"View Applications" 

 

12.[Application Pool] Get Application Pool Default Settings

 

$subsections = get-webconfiguration //applicationPoolDefaults//. -PSPATH iis:\

$subsections | foreach { $_.attributes | select name,value }

 
PS IIS:\> $subsections = get-webconfiguration //applicationPoolDefaults//.PS IIS:\> $subsections | foreach { $_.attributes | select name,value } Name                                    Value----                                    -----namequeueLength                             1000autoStart                               Trueenable32BitAppOnWin64                   FalsemanagedRuntimeVersion                   v2.0enableConfigurationOverride             TruemanagedPipelineMode                     0passAnonymousToken                      TrueidentityType                            2userNamepasswordloadUserProfile                         FalsemanualGroupMembership                   FalseidleTimeout                             00:20:00maxProcesses                            1shutdownTimeLimit                       00:01:30startupTimeLimit                        00:01:30pingingEnabled                          TruepingInterval                            00:00:30pingResponseTime                        00:01:30disallowOverlappingRotation             FalsedisallowRotationOnConfigChange          FalselogEventOnRecycle                       137memory                                  0privateMemory                           0requests                                0time                                    1.05:00:00value                                   11:59:00value                                   11:32:00loadBalancerCapabilities                1orphanWorkerProcess                     FalseorphanActionExeorphanActionParamsrapidFailProtection                     FalserapidFailProtectionInterval             00:05:00rapidFailProtectionMaxCrashes           5autoShutdownExeautoShutdownParamslimit                                   0action                                  0resetInterval                           00:05:00smpAffinitized                          FalsesmpProcessorAffinityMask                4294967295
 

logEventOnRecyle property value shows number value, which is not human-readable. You can get the text enum value by querying the specific property instead such as shown in the following:

 

get-webconfiguration //applicationPoolDefaults/recycling/@logEventOnRecycle

 
PS IIS:\> get-webconfiguration //applicationPoolDefaults/recycling/@logEventOnRecycleTime,Memory
 Related UI Task:"Set Application Pool Defaults..."  

 

13.[Application Pool] Set Application Pool Default Settings

 

Case1: Setting queueLength, which is “property” type

 

set-webconfigurationproperty /system.applicationHost/applicationPools/applicationPoolDefaults[1]/failure[1] -name rapidFailProtectionMaxCrashes -value 10

 
# You could get the section path of the target property programmaticallyPS IIS:\> get-webconfiguration //*[@rapidFailProtectionMaxCrashes] | foreach {$_.itemXPath}/system.applicationHost/applicationPools/applicationPoolDefaults[1]/failure[1]/system.applicationHost/applicationPools/add[@name='DefaultAppPool']/failure[1]/system.applicationHost/applicationPools/add[@name='Classic .NET AppPool']/failure[1] # Set the property value with the section pathPS IIS:\> set-webconfigurationproperty /system.applicationHost/applicationPools/applicationPoolDefaults[1]/failure[1] -name rapidFailProtectionMaxCrashes -value 10 NOTE: applicationPoolDefaults[1]/failure[1] is equivalent to “applicationPoolDefaults/failure.
 

Case2: Setting schedule, which is “element” type (shown as “Specific Times” in UI)

 

add-webconfiguration /system.applicationHost/applicationPools/applicationPoolDefaults/recycling/periodicRestart/schedule -value (New-TimeSpan -h 9 -m30)

 
# Add new Add element with a new-timespan value and add-webconfiguration cmdletPS IIS:\> add-webconfiguration /system.applicationHost/applicationPools/applicationPoolDefaults/recycling/periodicRestart/schedule -value (New-TimeSpan -h 9 -m30) # Confirm the new value is addedPS IIS:\> get-webconfiguration /system.applicationHost/applicationPools/applicationPoolDefaults/recycling/periodicRestart/schedule/add | select value value-----09:30:00
 Related UI Task:"Set Application Pool Defaults..." 

 

14.[Application Pool] Get configuration settings for a specific application pool

 

$configSection = "/system.applicationHost/applicationPools/add[@name='DefaultAppPool']//."

$subsections = get-webconfiguration $configSection -PSPath iis:\

$subsections | foreach { $_.attributes | select name,value }

 Or, you can use “*” instead of the full config section path: 

$subsections = get-webconfiguration '//*[@name="DefaultAppPool"]//.' -PSPath iis:\

$subsections | foreach { $_.attributes | select name,value }

 Related UI Task:"Advanced Settings..." 

 

15.[Application Pool] Set configuration settings for a specific application pool

 

Case1: Setting logEventOnRecycle, which is “enum property” type

 

$configSection = "/system.applicationHost/applicationPools/add[@name='DefaultAppPool']/recycling"

set-webconfigurationproperty $configSection -name logEventOnRecycle -value 1 -PSPath iis:\

 

NOTE: The value could be set with "Time" in the next version instead of 1 for the above example

 Related UI Task:"Advanced Settings..." 

 

16.[Application Pool] Get the list of application pools

 
Dir iis:\sites
 Related UI Task:"Sites" treeview 

 

17.[Sites] Create a new Web Site

 

Case1: Create web site with single binding

 

$binding = @{protocol="http";bindingInformation="*:80:hostname"}

new-item "iis:\sites\demoSite" -type site –physicalPath c:\demoSite -bindings $binding

 

Case2: Create web site with multiple binding and specific id

 

$binding = (@{protocol="http";bindingInformation="*:80:hostname"},@{protocol="http";bindingInformation="*:80:hostname2"})

new-item "iis:\sites\demoSite" -type site -physicalPath c:\demoSite -bindings $binding -id 555

 Or, you can use other task-based  cmdlet(s) instead: 

New-WebSite -Name DemoSite -Port 80 -HostHeader hostname –PhysicalPath c:\demoSite –ID 555

New-WebBinding -Site DemoSite -Port 80 -IPAddress * -HostHeader hostname2

 Related UI Task:"Add Web Site..." wizard 

 

18.[Sites] Set bindings

 

Case1: Create SSL Binding (127.0.0.1!443)

 
$certObect = get-itemcert:\LocalMachine\My\E48803C3A6DDC8F2BFE3D8B7B7D56BBA70270F92new-item IIS:\SslBindings\127.0.0.1!443 -value $certObect
 
PS IIS:\> dir cert:\LocalMachine\My     Directory: Microsoft.PowerShell.Security\Certificate::LocalMachine\My  Thumbprint                                Subject----------                                -------E48803C3A6DDC8F2BFE3D8B7B7D56BBA70270F92  CN=WMSvc-JHKIM-WTT3 PS IIS:\> $certObect = get-itemcert:\LocalMachine\My\E48803C3A6DDC8F2BFE3D8B7B7D56BBA70270F92 PS IIS:\> new-item IIS:\SslBindings\127.0.0.1!443 -value $certObect IP Address       Port Store            Sites----------       ---- -----            -----127.0.0.1        443  My
 

Case2: Set 'Bindings' property with multiple binding information including the SSL binding which was created above.

 

$newBinding = (@{protocol="http";bindingInformation="127.0.0.1:80:normalSite"},@{protocol="https";bindingInformation="127.0.0.1:443:securedSite"})

Set-itemproperty "IIS:\Sites\Default Web Site" -name bindings -value $newBinding

 Or, you can use other task-based  cmdlet(s) instead: 

New-WebBinding -Site "Default Web Site" -Port 443 -IPAddress 127.0.0.1 -HostHeader securedSite

 

NOTE: you can also use set-webconfiguration, set-webconfiguration or add-webconfigurationProperty.

 

Set-Webconfiguration '/system.applicationHost/sites/site[@name ="Default Web Site"]/bindings' -value $newBinding  -PSPath iis:\

 

Set-WebconfigurationProperty '/system.applicationHost/sites/site[@name ="Default Web Site"]' -name bindings.collection -value $newBinding -at 0  -PSPath iis:\

 

Add-WebconfigurationProperty '/system.applicationHost/sites/site[@name ="Default Web Site"]' -name bindings.collection -value @{protocol="https";bindingInformation="127.0.0.1:443:securedSite"} -at 0  -PSPath iis:\

 

Case3: Change a certain value of existing 'Bindings' property using other task-based  cmdlet.

 

Set-WebBinding -Site "Default Web Site" -Port 443 -IPAddress 127.0.0.1 -HostHeader securedSite -name Port -value 444

 

Case4: Removing binding information using other task-based  cmdlet.

 

Remove-WebBinding -Site "Default Web Site" -Port 443 -IPAddress 127.0.0.1 -HostHeader securedSite

 

Or, you can use Remove-WebConfigurationProperty

 

Remove-WebconfigurationProperty '/system.applicationHost/sites/site[@name="Default Web Site"]' -name Bindings.collection -at @{protocol="https";bindingInformation="127.0.0.1:443:securedSite"}  -PSPath iis:\

 

Case5: Clear all the binding information of a certain web site

 

Clear-Webconfiguration '/system.applicationHost/sites/site[@name="Default Web Site"]/bindings' -PSPath iis:\

 

NOTE: you can also use clear-itemproperty instead:

 

Clear-ItemProperty 'iis:\sites\Default Web Site' -name bindings

Related UI Task:"Bindings..." 

 

19.[Sites] Rename an Web Site

 

Rename-Item "iis:\sites\default web site" newWebSiteName

 Related UI Task:"Rename " 

 

20.[Sites] Remove an Web Site

 

Remove-Item "iis:\sites\default web site"

 Or, you can use other task-based  cmdlet(s) instead: 

Remove-WebSite " default web site"

 Related UI Task:"Remove " 

 

21.[Sites] Stop/Start/Restart Web Site

 

Start-WebItem "IIS:\Sites\Default Web Site"

Stop-WebItem "IIS:\Sites\Default Web Site"

Restart-WebItem "IIS:\Sites\Default Web Site"

 Or, you can use other task-based  cmdlet(s) instead: 

Start-WebSite "Default Web Site"

Stop-WebSite "Default Web Site"

Restart-WebSite "Default Web Site"

 Related UI Task:"Stop/Start/Restart" 

 

22.[Sites] Get the current status of Web Site

 

Get-WebItemState "IIS:\Sites\Default Web Site"

 Or, you can use other task-based  cmdlet(s) instead: 

Get-WebSiteState "Default Web Site"

 Related UI Task:"Stop/Start/Recycle" 

 

23.[Sites] Get Web Site Defaults Settings

 

$subsections = get-webconfiguration //siteDefaults//. -PSPATH iis:\

$subsections | foreach { $_.attributes | select name,value }

 
PS IIS:\> $subsections = get-webconfiguration //siteDefaults//. -PSPATH iis:\PS IIS:\> $subsections | foreach { $_.attributes | select name,value } Name                                    Value----                                    -----nameid                                      0serverAutoStart                         TruemaxBandwidth                            4294967295maxConnections                          4294967295connectionTimeout                       00:02:00logExtFileFlags                         2215887customLogPluginClsidlogFormat                               2directory                               %SystemDrive%\inetpub\logs\LogFilesperiod                                  1truncateSize                            20971520localTimeRollover                       Falseenabled                                 Trueenabled                                 Falsedirectory                               %SystemDrive%\inetpub\logs\FailedReq...maxLogFiles                             50maxLogFileSizeKB                        512customActionsEnabled                    FalseallowUTF8                               TrueserverAutoStart                         TrueunauthenticatedTimeout                  30controlChannelTimeout                   120dataChannelTimeout                      30disableSocketPooling                    FalseserverListenBacklog                     60minBytesPerSecond                       240maxConnections                          4294967295resetOnMaxConnections                   FalsemaxBandwidth                            4294967295matchClientAddressForPort               TruematchClientAddressForPasv               TruemaxCommandLine                          4096allowUnlisted                           TrueserverCertHashserverCertStoreName                     MYssl128                                  FalsecontrolChannelPolicy                    1dataChannelPolicy                       1clientCertificatePolicy                 0useActiveDirectoryMapping               FalsevalidationFlags                         0revocationFreshnessTime                 00:00:00revocationUrlRetrievalTimeout           00:01:00enabled                                 FalseuserName                                IUSRpassworddefaultLogonDomain                      NT AUTHORITYlogonMethod                             3enabled                                 FalsedefaultLogonDomainlogonMethod                             3enabled                                 FalseimpersonationLevel                      1exitMessagegreetingMessagebannerMessagemaxClientsMessagesuppressDefaultBanner                   FalseallowLocalDetailedErrors                TrueexpandVariables                         FalsekeepPartialUploads                      FalseallowReplaceOnRename                    FalseallowReadUploadsInProgress              FalseexternalIp4Addressmode                                    4adUserNameadPasswordadCacheRefresh                          00:01:00showFlags                               0virtualDirectoryTimeout                 5logExtFileFlags                         14716367directory                               D:\inetpub\logs\LogFilesperiod                                  1truncateSize                            20971520localTimeRollover                       Falseenabled                                 TrueselectiveLogging                        7
 Related UI Task:"Set Web Site Defaults..." 

 

24.[Sites] Set Web Site Default Settings

 

Case1: Setting connectionTimeout

 

set-webconfigurationproperty "/system.applicationHost/sites/siteDefaults[1]/limits[1]" -name connectionTimeout -value (New-TimeSpan -sec 130)

 
# You could get the section path of the target property programmaticallyPS IIS:\> get-webconfiguration //*[@connectionTimeout] | foreach {$_.itemxpath}/system.applicationHost/webLimits/system.applicationHost/sites/siteDefaults[1]/limits[1]/system.applicationHost/sites/site[@name='Default Web Site' and @id='1']/limits[1]  # Set the property value with the section pathPS IIS:\> set-webconfigurationproperty "/system.applicationHost/sites/siteDefaults[1]/limits[1]" -name connectionTimeout -value (New-TimeSpan -sec 130)
 Related UI Task:"Set Web Site Defaults..." 

 

25.[Sites] Get configuration settings for a specific web site

 

$configSection = "/system.applicationHost/sites/site[@name='Default Web Site']//."

$subsections = get-webconfiguration $configSection -PSPath iis:\

$subsections | foreach { $_.attributes | select name,value }

 Or, you can use “*” instead of the full config section path: 

$subsections = get-webconfiguration '//*[@name="Default Web Site"]//.' -PSPath iis:\

$subsections | foreach { $_.attributes | select name,value }

 Related UI Task:"Advanced Settings..." 

 

26.[Sites] Set configuration settings for a specific web site

 

Case1: Setting maxLogFiles

 

$configSection = "/system.applicationHost/sites/site[@name='Default Web Site' and @id='1']/traceFailedRequestsLogging"

set-webconfigurationproperty $configSection -name maxLogFiles -value 60 -PSPath iis:\

 

If you are trying to change basic properties, you could also use set-itemProperty as shown in the following:

 

Case2: 'Application Pool' property

 
Set-Itemproperty IIS:\Sites\DemoSite -name applicationPool -value demo

AppPool

 

Case3: 'Physical Path' property

 

set-itemproperty IIS:\Sites\DemoSite -name physicalPath -value c:\demoSite2

 

Case4: 'username' property

 

set-itemproperty IIS:\Sites\DemoSite -name userName -value newUserId

 

Case5: 'password' property

 

set-itemproperty IIS:\Sites\DemoSite -name password -value newPassword

 Related UI Task:"Advanced Settings..." 

 

27.[Sites] Set Failed Request Tracing for a specific web site

 

Case1: Enable Freb for a specific web site with setting maxLogFiles and directory

 

$configSection = "/system.applicationHost/sites/site[@name='Default Web Site' and @id='1']/traceFailedRequestsLogging"

set-webconfigurationproperty $configSection -name maxLogFiles -value 60 -PSPath iis:\

set-webconfigurationproperty $configSection -name directory -value c:\MyFailedReqLogFiles -PSPath iis:\

 Or, you can use other task-based  cmdlet(s) instead: 

Enable-Freb -Site "default web site" -Directory "c:\MyFailedReqLogFiles" -MaxLogFileSize 555

 

Case2: Disable Freb for a specific web site

 

$configSection = "/system.applicationHost/sites/site[@name='Default Web Site' and @id='1']/traceFailedRequestsLogging"

set-webconfigurationproperty $configSection -name enabled -value false -PSPath iis:\

 Or, you can use other task-based  cmdlet(s) instead: 

Disable-Freb -Site "default web site"

 

Case3: Clear Freb data for a specific web site

 

If you use Enable-Freb, it creates following default setting of Freb settings for the specified sites. We can clear them by this way.

 
<?xml version="1.0" encoding="UTF-8"?><configuration>    <system.webServer>        <tracing>            <traceFailedRequests>                <add path="*">                    <traceAreas>                        <add provider="WWW Server" areas="Authentication,Security,Filter,StaticFile,CGI,Compression,Cache,RequestNotifications,Module" verbosity="Verbose" />                        <add provider="ASP" verbosity="Verbose" />                        <add provider="ISAPI Extension" verbosity="Verbose" />                        <add provider="ASPNET" areas="Infrastructure,Module,Page,AppServices" verbosity="Verbose" />                    </traceAreas>                    <failureDefinitions timeTaken="00:00:30" statusCodes="500" verbosity="Warning" />                </add>            </traceFailedRequests>        </tracing>    </system.webServer></configuration>
 
Clear-WebConfiguration /system.webServer/tracing/traceFailedRequests -PSPath "iis:\sites\default web site"
 Or, you can use other task-based  cmdlet(s) instead: 

Clear-FrebData -Site "default web site"

 Related UI Task:"Advanced Settings..." 

 

28.[Management] Read default feature Delegation settings

 

Case1: Dump all sectionGroups

 

get-webconfigurationproperty / -name sectiongroups

 

Case2: Dump specific sectionGroup such as "system.applicationHost"

 

get-webconfigurationproperty / -name sectiongroups["system.applicationHost"]

 

Case3: Dump all sections under "/" group

 

get-webconfigurationproperty / -name Sections

 

NOTE: You will see empty value because IIS configuration system does not have section under "root" level by default

 

Case4: Dump all sections under specific sectionGroup such as "system.webServer"

 

$sections = get-webconfigurationproperty /system.webserver -name Sections

$sections | select Name,OverrideModeDefault

 
PS IIS:\> $sections = get-webconfigurationproperty /system.webserver -name SectionsPS IIS:\> $sections | select Name,OverrideModeDefault Name                                                        OverrideModeDefault----                                                        -------------------httpProtocol                                                AllowhttpErrors                                                  DenyhttpRedirect                                                AllowglobalModules                                               Denycgi                                                         DenyserverRuntime                                               DenydirectoryBrowse                                             AllowurlCompression                                              AllowhttpLogging                                                 Denymodules                                                     DenyodbcLogging                                                 Denyvalidation                                                  AllowfastCgi                                                     Denyhandlers                                                    DenyhttpTracing                                                 DenystaticContent                                               AllowisapiFilters                                                DenydefaultDocument                                             Allowasp                                                         DenyhttpCompression                                             DenyserverSideInclude                                           Denycaching                                                     Allow
 

NOTE: Now you can see the default override mode for "ASP" config section is deny, which means we can configure ASP related properties only for 'server' level

 Related UI Task:UI Feature: "Feature Delegation" page 

 

29.[Management] Add/Remove customized IIS config section

 

Case1: Add "myGroup" sectiongroup under root

 

add-webconfigurationproperty / -name SectionGroups -value myGroup

 

Case2: Add "mySection" section under the myGroup sectiongroup which was created above

 

add-webconfigurationproperty /myGroup -name Sections -value mySection

 

Case3: Set OverrideModeDefault for the newly created section, "mySection"

 

set-webconfigurationproperty /myGroup -name Sections["mySection"].OverrideModeDefault -value Deny

 

Case4: Set AllowDefinition for the newly created section, "mySection"

 

set-webconfigurationproperty /myGroup -name Sections["mySection"].AllowDefinition -value AppHostOnly

 

Case5: Set AllowLocation for the newly created section, "mySection"

 

set-webconfigurationproperty /myGroup -name Sections["mySection"].AllowLocation -value false

 

Case6: Remove the "mySection" section which were created above

 

remove-webconfigurationproperty /myGroup -name Sections -at mySection

 

Case7: Remove the "myGroup" sectiongroup which were created above

 

remove-webconfigurationproperty / -name SectionGroups -at myGroup

 Related UI Task:UI Feature: UI has no related task for this. 

 

30.[Management] Configure Feature Delegation related settings

 

NOTE: Before changing delegation setting of a config section, you would need to remove previously configured properties and elements of the section and re-configure them again after the delegation setting is updated.

 

This is an example of how to remove ASP sections using clear-webconfiguration cmdlet:

 

clear-webconfiguration /system.webServer/asp -pspath MACHINE/WEBROOT/A

PPHOST/testSite

clear-webconfiguration /system.webServer/asp -pspath MACHINE/WEBROOT/A

PPHOST

 
# Get the list of previously configured items using -recurse optionPS IIS:\> get-webconfiguration //asp -Recurse SectionPath                             PSPath-----------                             ------/system.webServer/asp                   MACHINE/WEBROOT/APPHOST/system.webServer/asp                   MACHINE/WEBROOT/APPHOST/testSite # Clear those items using clear-webconfigurationPS IIS:\> clear-webconfiguration /system.webServer/asp -pspath MACHINE/WEBROOT/APPHOST/testSitePS IIS:\> clear-webconfiguration /system.webServer/asp -pspath MACHINE/WEBROOT/APPHOST
 

Case1: Read the current Delegation setting of ASP feature for 'server' level

 

get-webconfiguration //asp iis:\ | select OverrideMode

 
PS IIS:\> get-webconfiguration //asp iis:\ | select OverrideMode                                                                                                           OverrideMode------------Inherit
 

NOTE: The value "inherit" means it uses the default override mode and it is actually "Deny" in the default IIS configuration

 

Case2: Set "Read-Write" for ASP feature for 'server' level

 

set-webconfiguration //asp -metadata overrideMode -value Allow -PSPath iis:\

 

Case3: Set "Not Delegated" for ASP feature for 'server' level

NOTE: "Not Delegated" task is only applicable to IIS UI world. Please use "Read Only" which is explained below.

 

Case4: Set "Read Only" for ASP feature for 'server' level

 

set-webconfiguration //asp -metadata overrideMode -value Deny -PSPath iis:\

 

Case5: Set "Reset to Inherited" for ASP feature for 'server' level

 

set-webconfiguration //asp -metadata overrideMode -value Inherit -PSPath iis:\

 

Case6: Change Delegation settings for 'site' level

 

set-webconfiguration //asp -metadata overrideMode -value Inherit -PSPath "iis:\sites\default web site"

 

Case7: Change Delegation settings for 'site' level using location

 

set-webconfiguration //asp -metadata overrideMode -value Inherit -PSPath "iis:\sites" -Location "default web site"

 Related UI Task:UI Feature: "Feature Delegation" page 

 

31.[IIS] Configure Clasic ASP properties

 

Case1: Read all ASP settings from 'server' level

 

$subsections = get-webconfiguration //asp//. -PSPATH iis:\

$subsections | foreach { $_.attributes | select name,value }

 

Case2: Read all ASP settings from 'web site' level such as "Default Web Site"

 

$subsections = get-webconfiguration //asp//. -PSPATH "iis:\sites\default web site"

$subsections | foreach { $_.attributes | select name,value }

 

Case3: Read all ASP settings from 'web application' level such as "DemoApplication "

 

$subsections = get-webconfiguration //asp//. -PSPATH "iis:\sites\default web site\demoapplication"

$subsections | foreach { $_.attributes | select name,value }

 

Case4: Read all ASP settings from 'file' level which is under an Web Site

 

$subsections = get-webconfiguration //asp//. -PSPATH "iis:\sites\default web site" -location iisstart.htm

$subsections | foreach { $_.attributes | select name,value }

 

Case5: Write an ASP setting, keepSessionIdSecure, for 'server' level

 

set-webconfigurationproperty "/system.webServer/asp/session[1]" -name keepSessionIdSecure -value true -PSPath iis:\

 
# You could get the section path of the target property programmaticallyPS IIS:\> get-webconfiguration //*[@keepSessionIdSecure] | foreach {$_.itemxpath}/system.webServer/asp/session[1] # Set the property value with the section pathPS IIS:\> set-webconfigurationproperty "/system.webServer/asp/session[1]" -name keepSessionIdSecure -value true -PSPath iis:\
 

Case6: Write an ASP setting, keepSessionIdSecure, for 'site' level

 

set-webconfigurationproperty "/system.webServer/asp/session[1]" -namekeepSessionIdSecure -value true -PSPath "iis:\sites\default web site"

 

Case5: Write an ASP setting, keepSessionIdSecure, for 'file' level which is under an Web Site

 

set-webconfigurationproperty "/system.webServer/asp/session[1]" -name keepSessionIdSecure -value true -PSPath "iis:\sites\default web site" -location iisstart.htm

 Related UI Task:UI Feature: "ASP" page 

 

32.[IIS] Configure Authentication properties

 

Case1: List all of authentications and from 'server' level

 

get-webconfiguration /system.webServer/security/authentication/*[@enabled] -PSPath iis:\ | select ItemXPath,enabled

 

Case2: List all of authentications and from 'site' level

 

get-webconfiguration /system.webServer/security/authentication/*[@enabled] -PSPath "iis:\sites\default web site"| select ItemXPath,enabled

 

NOTE: You can also get from other levels adjusting the value -PSPath and -Location parameter values

 

Case3: Get all of Anonymous authentication properties from 'server' level

 

$attributes = (Get-WebConfiguration /system.webServer/security/authentication/anonymousAuthentication -PSPath iis:\).attributes

$attributes | select name,value

 

NOTE: You can also get from other levels adjusting the value -PSPath and -Location parameter values

 

Case4: Change userName property for Anonymous authentication properties from 'server' level

 

Set-WebConfigurationproperty system.webServer/security/authentication/anonymousAuthentication -name userName -value "" -PSPath iis:\

 

NOTE: You can also set for other levels adjusting the value -PSPath and -Location parameter values

 Related UI Task:UI Feature: "Authentication" page 

 

33.[IIS] Configure Module elements and properties which are configured in globalModules section

 

Case1: List all native modules

 

(Get-WebConfiguration //globalmodules).collection -PSPath iis:\

 

Case2: Add a new native modue at the bottom index of the existing modules

 

Add-WebConfigurationProperty //globalmodules -name collection -value @{name='testmodule';image='c:\test.dll'} -PSPath iis:\

 Or, you can use other task-based  cmdlet(s) instead: 

New-WebModule -Name testmodule -Image c:\test.dll -Precondition "integratedMode"

 

Case3: Add a new native modue at the top index of the existing modules

 

Add-WebConfigurationProperty //globalmodules -name collection -value @{name='testmodule';image='c:\test.dll'} -at 0 -PSPath iis:\

 

Case4: Remove a native modue with a number index value

 

Remove-WebConfigurationProperty //globalmodules -name collection -at 0 -PSPath iis:\

 

Case5: Remove a native modue with a hashtable index value

 

Remove-WebConfigurationProperty //globalmodules -name collection -at @{name='testmodule';image='c:\test.dll'} -PSPath iis:\

 Or, you can use other task-based  cmdlet(s) instead: 

Remove-WebModule -Name testmodule

 

Case6: Get the attributes for a specific module

 

$modules = (get-webconfiguration //globalmodules -PSPath iis:\).collection

$modules | foreach {if ($_.name -eq "cgiModule") { $_.attributes | select name, value}}

 

Case7: Change an attribute value for a specific module

 

Get-Webconfigurationproperty '//globalmodules/add[@name="CgiModule"]' -name image -PSPath iis:\

Set-Webconfigurationproperty '//globalmodules/add[@name="CgiModule"]' -name image -value %windir%\System32\inetsrv\cgi.dll -PSPath iis:\

 Related UI Task:UI Feature: "Modules" page 

 

34.[IIS] Configure Module elements and properties

 

Case1: Enable/Disable a native modue

 

Add-WebConfigurationProperty //modules -name collection -value @{name='testmodule';lockItem='true'}  -at 0 -PSPath iis:\

 Or, you can use other task-based  cmdlet(s) instead: 

Enable-WebModule -Name testModule

 

Case2: Add a new managedModule

 

Add-WebConfigurationProperty //modules -name collection -value @{name='newManagedModule';type='Microsoft.IIS.DemoModule'}  -PSPath iis:\

 Or, you can use other task-based  cmdlet(s) instead: 

New-Managedwebmodule -name newManagedModule -Type Microsoft.IIS.DemoModule

 

Case3: Disable module by removing the module element from the <modules> section

 

Remove-WebConfigurationProperty //modules -name collection -at @{name='testmodule';lockItem='true'}  -PSPath iis:\

 Or, you can use other task-based  cmdlet(s) instead: 

Disable-WebModule -Name testModule

 

Case4: List all of enabled modules from 'server' level

 

(get-webconfiguration //modules -PSPath iis:\).collection -PSPath iis:\

Or, you can use other task-based  cmdlet(s) instead: 

Get-WebModule -PSPath iis:\ -enabled

 

Case5: Get the attributes for a specific module

 

$modules = (get-webconfiguration //modules -PSPath iis:\).collection

$modules | foreach {if ($_.name -eq "cgiModule") { $_.attributes | select name, value}}

 

Case6: Change an attribute value for a specific module

 

Get-Webconfigurationproperty '//modules/add[@name="CgiModule"]' -name lockItem -PSPath iis:\

Set-Webconfigurationproperty '//modules/add[@name="CgiModule"]' -name lockItem -value true -PSPath iis:\

 Related UI Task:UI Feature:"Modules" page 

 

35.[IIS] Change order Module elements and Revert To Inherit for a site level

 

Case1: Move testmodule to bottom index

 

# remove the target item and then re-create the item

Remove-WebConfigurationProperty //modules -name collection -at @{name='testmodule';lockItem='true'}  -PSPath iis:\

 

Add-WebConfigurationProperty //modules -name collection -value @{name='testmodule';lockItem='true'}  -PSPath iis:\

 

Case2: Revert To Inherit for 'site' level

 

Clear-WebConfiguration //modules -name -PSPath 'iis:\sites\default web site'

 Related UI Task:UI Feature:"Modules" page 

 

36.[IIS] Get the list of worker processes and requests which is running on an Application Pool

  

get-webrequest -Process 3644 -AppPool defaultapppool

 
### Get the process information of DefaultAppPoolPS IIS:\AppPools\DefaultAppPool\WorkerProcesses> dir Process  State      Handles  Start TimeId-------- -----      -------  ----------3644     Running    310      7/24/2008 4:23:22 PM ### Call Get-WebRequest to get the list of requests using the process informationPS IIS:\AppPools\DefaultAppPool\WorkerProcesses> get-webrequest -Process 3644 -AppPool defaultapppool  requestId    : fe00000080000466connectionId : fe00000060000463verb         : GETurl          : /long.aspxsiteId       : 1 ### Or, you can use GetRequsts() method:PS IIS:\AppPools\DefaultAppPool\WorkerProcesses> (get-item 3644).getrequests($null)  requestId    : fe00000080000469connectionId : fe00000060000463verb         : GETurl          : /long.aspxsiteId       : 1
 Related UI Task:UI Feature: "Worker Processes" page

 


Developing IIS Native module

$
0
0

I have started to learn IIS Native API (C++) and hope to share what I have learned. This blog is targeting for beginner programmers who want to develope IIS native module in C++ for the first time.

What I will cover here
  • Understanding Global Module/Module/Handler
  • Quick reference of IIS Native API 
  • IIS Core system 

Understanding Global Module/Module/Handler

In order to learn IIS native API, I tried to create a small module with various sample codes and found some cases of not working. In the explanation of the popular example module, I had learned that I needed to register the module onto both <globalModules> and <modules> section. And it worked with no question. 

  • TIP
    • My first module did not work because I complied the module as x86 version and wanted to make it run on amd64 bit machine. The problem was solved with compiling the module as 64 bit compilation)
    • Another mistake happened when I used the full path of my module dll file which is created by Visual Studio without access permission. I had to give the access permission for the users group for the directory to solve the error such as "The Module DLL c:\work\IISNativeModule\Debug\MyModule.dll failed to load. The data is the error." which was shown in the event viewer.

My first module was to subscribe a single global level event such as GL_PRE_BEGIN_REQUEST and it worked in that way. And soon I realized the module works even though I removed the line of module from the <modules> section and I realized that if the module needs to subscribe only global level events, we don't need to register module onto <modules> section. This is how I learned the difference between module and global module in configuration wide.

I also tried to create another module which subscribes a single request level event such as RQ_EXECUTE_REQUEST_HANDLER. But this time, the module did not work even though I registered in the both <globalModules> and <modules> section.
I realized that actually I had made a handler module even though I thought I was making an ordinary module and I had to configure addional thing. Handler module is a special module which subscribes only the RQ_EXECUTE_REQUEST_HANDLER event. So, so the problem had to be solved by registering the module to <handlers> section.

But, I ran into another problem after I put my module, "TestModule", at the end of the value of modules attribute like this.

            <add name="StaticFile" path="*" verb="*" modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule, TestModule" resourceType="Either" requireAccess="Read" />

When I sent a request but the module was not invoked. And the problem was solved by changing the order of the module names like this.

            <add name="StaticFile" path="*" verb="*" modules=" TestModule ,StaticFileModule,DefaultDocumentModule,DirectoryListingModule" resourceType="Either" requireAccess="Read" />

That means, if there are multiple modules in a single handler item such as the above case, the previous modules can determine to make the next module run or not. And that's why my module was not picked up.

If you want to know more about this topic, refer to http://blogs.msdn.com/b/tmarq/archive/2007/08/30/iis-7-0-asp-net-pipelines-modules-handlers-and-preconditions.aspx.


Quick reference of IIS Native API

While I read MSDN, the number of classes/interfaces/struct/constants made me confused and overwhelmed. So, to get rid of the complexity, I tried to summarize the relationship between each interfaces and event handlers. After that, I felt it was not that complicated actually. Here is my version of summurized set of API, which I attached here for you to find the overal view of whole API sets.

1) Classes which are implemented in global or regular module (or handler module)

  • CGlobalModule, which is for global module
  • IHttpModuleFactory, which is a class factory of regular module
  • CHttpModule, which is for regular module

2) The order of creating the class objects

  • All objects should be created when RegisterModule() function, which is the unique exported DLL function of the module
  • CGlobalModule object is created at the heap memory and then its pointer is passed to IIS worker process by calling SetRequestNotifications() function
  • IHttpModuleFactory object is also created at the heap memory and then its pointer is passed to IIS worker process by calling SetGlobalNotifications() function
  • HttpModule object is created when IHttpModuleFactory object's GetHttpModule() function is called by IIS worker process
  • NOTE:
  • a. When GetHttpModule() is called, which happens for once for every request, we should create the HttpModule object every time and the object should be deleted if it was created in the heap memory when each request life cycle is finished
  • b. If you want to create a the module in heap, not stack memory, you can use IModuleAllocator interface to allocate memory of request pool
  • c. CGlobalModule event handler functions

3) Handler function name ant its event provider type

  • OnGlobalApplicationPreload
    • IGlobalApplicationPreloadProvider
  • OnGlobalApplicationResolveModules
    • IHttpApplicationResolveModulesProvider
  • OnGlobalApplicationStart
    • IHttpApplicationStartProvider
  • OnGlobalApplicationStop
    • IHttpApplicationStopProvider
  • OnGlobalCacheCleanup
    • void
  • OnGlobalCacheOperation
    • ICacheProvider
  • OnGlobalConfigurationChange
    • IGlobalConfigurationChangeProvider
  • OnGlobalCustomNotification
    • ICustomNotificationProvider
  • OnGlobalFileChange
    • IGlobalFileChangeProvider
  • OnGlobalHealthCheck
    • void
  • OnGlobalPreBeginRequest
    • IPreBeginRequestProvider
  • OnGlobalRSCAQuery
    • IGlobalRSCAQueryProvider
  • OnGlobalStopListening
    • IGlobalStopListeningProvider
  • OnGlobalThreadCleanup
    • IGlobalThreadCleanupProvider
  • OnGlobalTraceEvent
    • IGlobalTraceEventProvider
  • OnGlobalTerminate
    • void
  • Return value which are applied to all event handlers
    • GL_NOTIFICATION_CONTINUE
    • GL_NOTIFICATION_HANDLED, which indicates to stop IIS pipeline

4) CHttpModule event handler functions

  • Handler function name ant its event provider type
    • OnAcquireRequestState
      • OnPostAcquireRequestState
    • OnAsyncCompletion
    • OnAuthenticateRequest  (IAuthenticationProvider)
      • OnPostAuthenticateRequest
    • OnAuthorizeRequest
      • OnPostAuthorizeRequest
    • OnBeginRequest
      • OnPostBeginRequest
        • OnPostEndRequest
    • OnCustomRequestNotification (ICustomNotificationProvider)
    • OnEndRequest
    • OnExecuteRequestHandler
      • OnPostExecuteRequestHandler
    • OnLogRequest
      • OnPostLogRequest
    • OnMapPath (IMapPathProvider)
    • OnMapRequestHandler
      • OnPostMapRequest
    • OnPreExecuteRequestHandler
      • OnPostPreExecuteRequestHandler
    • OnReleaseRequestState
      • OnPostReleaseRequestState
    • OnResolveReuqestCache
      • OnPostResolveRequestCache
    • OnUpdateRequestCache
      • OnPostUpdateRequestCache
    • OnReadEntity (IReadEntityProvider)
    • OnSendResponse (ISendResponseProvider)
  • Return value which are applied to all event handlers
    • RQ_NOTIFICATION_CONTINUE
    • RQ_NOTIFICATION_FINISH, which indicates to stop IIS pipeline from request level
    • RQ_NOTIFICATION_PENDING, which indicates to stop IIS pipeline temporarily while module's executing its own task asynchronously.  There are two ways to do this such as using IHttpContext::ExecuteRequest and OnAyncCompletion() and IHttpContext::PostCompletion()

5) IHttpEventProvider and derived interfaces

  • IHttpEventProvider
    • IAuthenticationProvider
    • ICacheProvider
      • IHttpCacheKey  <== GetCacheKey()
        • IFileKey
        • IHttpTokenKey
        • IUriKey
      • IHttpCacheSpecificData  <== GetCacheRecord()
        • IHttpTokenEntry
    • ICustomNotificationProvider
    • IGlobalApplicationPreloadProvider
      • IGlobalApplicationPreloadProvider2
    • IGlobalConfigurationChangeProvider
    • IGlobalFileChangeProvider
      • IHttpFileMonitor  <== GetFileMonitor()
    • IGlobalRscaQueryProvider
    • IGlobalStopListeningProvider
    • IGlobalThreadCleanupProvider
    • IGlobalTraceEventProvider
    • IHttpApplicationProvider
    • IHttpApplicationResolveModulesProvider
    • IPreBeginRequestProvider
    • ISendResponseProvider
    • IMapHandlerProvider
    • IMapPathProvider
    • IReadEntityProvider
    • IHttpApplicationStartProvider

6) Relationship between Interfaces

  • IHttpCompletionInfo  <== CHttpModule::OnAsyncCompletion()
    • IHttpCompletionInfo2
  • IHttpContext
    •  IHttpApplication  <== GetApplication()
      • IHttpApplication2
    • IHttpConnection <== GetConnection()
    • IHttpFileInfo   <== GetFileInfo()
    • IMetadataInfo   <= GetMetadata()
      • IReferencedMetadataInfo
    • IHttpModuleContextContainer  <== GetModuleContextContainer()
      • IHttpStoredContext <== GetModuleContext()
        • IWebSocketContext
        • IHttpConnectionStoredContext
      • IDispensedHttpModuleContextContainer
    • IHttpSite  <== GetSite()
    • IHttpUser  <== GetUser()
    • IHttpTraceContext  <== GetTraceContext()
    • IHttpUrlInfo  <== GetUrlInfo()
    • IHttpResponse  <== GetRespons()
      • IHttpCachePolicy  <== GetCachePolicy()
        • IHttpCachePolicy2
      • IHttpResponse2
    • IHttpRequest <== GetRequest()
      • IHttpRequest2
        • IHttpRequest3
    • IScriptMapInfo <== GetScriptMap()
    • IHttpContext2
      • IHttpContext3
        • INamedContextContainer <== GetNamedContextContainer()
  • IHttpModuleRegistrationInfo
    • IHttpModuleFactory ==> SetRequestNotifications()
      • IModuleAllocator <== GetHttpModule()
  • IHttpServer <== RegisterModule
    • IHttpServer2
    • IHttpPerfCounterInfo  <== GetPerfCounterInfo()   (IHttpSite::GetPerfCounterInfo() has the function)

IIS Core system

While summarizing the whole IIS native API, there are another confusing thing regarding the return value of the event handler.
At first, I imagined there should be only two such as "Continue" and "Finish", one for succes and the other for failure. But I realized that there was one more return value such as "RQ_NOTIFICATION_PENDING".
MSDN explains that it is used for asynchronous task handling but it was not that helpful because I didn't know how IIS and module should work together. 
So before understanding that, I had to make some curiosity about how IIS actually works and finally I managed to make some big ficture of IIS internal system and even made a very simple program which explains the relationship between the important Interface classes and our module classes which we should develop. The below attached code is compliable code in any C++ compiler. I just wanted to create my own simplified version of important IIS native API interfaces and classes. The purpose of the small program was to simulate how IIS handles the request and call IIS modules in its module pipeline, supposing there is only one module. Actual life cycle of request would be like as the following steps though:

  • IIS reads the applicationhost.config and prepare a list data structure of module objects in order to make all of the modules work for the request; Each module object implement event handler functions.
  • Now, IIS is ready and OS kernel system such as HTTP receive a request from wire and passes the request object to IIS
  • And then IIS creates a HttpContext object and copy the pointer of the request object to the HttpContext object, which will be used by modules
  • IIS creates a IISEventHandler object and the pointer of the HttpContext object is also copied to it
  • IIS call the event handler function of each module with the parameter of the IISEventHandler object
  • Each module participate in manipulating the request object and response body in its event handler functions
  • Once all modules finish the event handler functions, IIS give the response body to OS kernel system such as HTTP service

Summary

Today, I tried to review what I learned while trying the sample example codes of http://msdn.microsoft.com/en-us/library/aa347664(v=vs.90).aspx (IIS Native-Code Extensibility API Reference).
In the next time, I will write my own module to experiment more and share about that.

Source code of IIS and module simulation

#include "stdafx.h"
#include <iostream>
using namespace std;

class IHttpContext
{
public:
 virtual void SetHttpRequest(int newValue) = 0; 
};

class IHttpEventProvider
{
public: 
 virtual IHttpContext* GetHttpContext() = 0; 
};

class HttpContext : IHttpEventProvider, IHttpContext
{
private:
 int* _pHttpRequest; 

public:
 HttpContext(int* pHttpRequest) : _pHttpRequest(pHttpRequest)
 {  
 }

 void SetHttpRequest(int newValue)
 {
  *_pHttpRequest = newValue;
 }

 IHttpContext* GetHttpContext()
 {
  return this;
 }
};

class HttpEventProvider: IHttpEventProvider
{
private:
 IHttpContext* _pHttpContext;

public:
 HttpEventProvider(IHttpContext* pHttpContext) : _pHttpContext(pHttpContext)
 {
 }
 
 virtual IHttpContext* GetHttpContext()
 {
  return _pHttpContext;
 }
};

class IModule
{
public:
 virtual void OnBeginRequest(IHttpEventProvider* provider) = 0; 
};

class Module : IModule
{
public:  
 void OnBeginRequest(IHttpEventProvider* pHttpEventProvider)
 { 
  IHttpContext* pHttpContext = pHttpEventProvider->GetHttpContext();
  pHttpContext->SetHttpRequest(3);  
 }
};

int _tmain(int argc, _TCHAR* argv[])
{
  // Step 1.
 // let's suppose httpRequest object is integer value and was created in the beginning.
 // In actual world, the request object is created by http sys service for every request
 int httpRequest = 0; 
 cout << "Original Request: " << httpRequest << endl;

 // Step 2.
 // Now, IIS create the module object here to process the request.
 //In the actual world, it was done by IIS's calling the IHttpModuleFactory::GetModule() method in each module .dll file.
 Module* pModule = new Module(); 

 // Step3.
 // After creating module object, IIS create HttpContext object with copying the httpRequest object inside it.
 HttpContext* pHttpContext = new HttpContext(&httpRequest);

 // Step4
 // And then, IIS creates httpEventProvider object, which will be used by the parameter object of the event handler function which is implemented in each module .dll file
 // As you can see here, the HttpContext object information copied to httpEventProvider object so that event handler can access the httpContext object
 HttpEventProvider httpEventProvider((IHttpContext*) pHttpContext);

 // Step5
 // IIS creates state machine which invokes each deterministic request level events handler which is implemented in each module .dll file.
 // In actual world, there are global level event and non-deterministic request level events and they are fired outside of this state machine.
 IModule* pIModule;
 pIModule = (IModule*) pModule;  
 pIModule->OnBeginRequest((IHttpEventProvider *) pHttpContext);

 // Step6
 // Now the state machine is finished and then response object is passed to the http sys service and it transfer it to the client which started the httpRequest.
 cout << "Modified request by module: " << httpRequest << endl;
 
 // Step7
 // After all of the request is finished, the httpContext and module object is deleted to clean up
 delete pModule;
 delete pHttpContext;

 // In actual world, the event handler function can be implemented to support to handle asyncronous tasks but it wasn't explained here. I will explain it later.
 return 0;
}

IIS Powershell: Getting config section names and attributes names dynamically

$
0
0

IIS Powershell provider cmdlets require the config section path for the -filter parameter and the attribute names while getting/setting attribute value.

But it is not easy to memorize the full configuration path or attribute names for each config section.

So, I have created a utility method and a useful variable, such as $iis, and I put the full source code below so that you can customize if you want.

How to use this tool.

  1. Start powershell.exe
  2. Copy the below code and paste onto the powershell window to register the one utility function, Get-WebSchema, and to create a powershell variable, $iis with using the utility function
  3. Try to run the Example Scenario 6~9 and you will see how you can use this tool with the IIS Powershell cmdlets. (NOTE: you will know you can use the auto-tab funcationality while using the $iis variable, which is what I told about getting config section names and attribute names dynamically as the following example:

    # Ex.) without using $iis variable; users should know the full config path and attribute name
    >> PS C:\Windows\system32> Get-WebConfigurationProperty -filter /system.webServer/security/authentication/basicAuthentication -name enabled

    # Ex.) using $iis variable; users can use the auto-tab to get the config section name string using $iis
    >> Get-WebConfigurationProperty -filter $iis.basicAuthentication -name $iis.basicAuthentication._enabled

####  Copy and paste from here!!!
#
#     -------------------------- EXAMPLE 1 --------------------------
#     C:\> Get-WebSchema -list
#     This command retrieves the list of schema files that are available.
#
#     -------------------------- EXAMPLE 2 --------------------------
#     C:\> Get-WebSchema -list -fileName "$env:windir\system32\inetsrv\config\schema\IIS_schema.xml"
#     This command retrieves the list of sections that are available for IIS_Schema.xml file.
#
#     -------------------------- EXAMPLE 3 --------------------------
#     C:\> Get-WebSchema -list -fileName "$env:windir\system32\inetsrv\config\schema\IIS_schema.xml" -sectionName system.webServer/asp
#     This command retrieves an xml node object for the asp section in Iis_Schema.xml file.
#
#     -------------------------- EXAMPLE 4 --------------------------
#     C:\> Get-WebSchema -fileName "$env:windir\system32\inetsrv\config\schema\IIS_schema.xml" -sectionName system.webServer/asp
#     This command list all config information (Ie. attribute/method/element/collection) of the asp section
#
#     -------------------------- EXAMPLE 5 --------------------------
#     C:\> Get-WebSchema -fileName "$env:windir\system32\inetsrv\config\schema\IIS_schema.xml"
#     This command list all config information (Ie. attribute/method/element/collection) of the IIS_Schema file
#
#     -------------------------- EXAMPLE 6 --------------------------
#     C:\> $iis
#     This command will dump all available config sections
#
#     -------------------------- EXAMPLE 7 --------------------------
#     C:\> $iis.site
#     This command will return string value of the full config path such as system.applicationHost/sites/site
#
#     -------------------------- EXAMPLE 8 --------------------------
#     C:\> $iis.appSettings._file
#     This command will return string value of the attribute name, such as "file", of the appSettings config section.
#     (NOTE: for quick find attribute name, I put "_" string at the beginning of attribute name.
#     For the example, $iis.appSettings._<TAB> will show $iis.appSettings._file.

function global:Get-WebSchema()
{
    param(
        [string]$fileName=$null,
        [string]$sectionName=$null,
        [object]$nodeObject=$null,
        [switch]$list,
        [switch]$verbose
    )

    if ($list -and $sectionName -and -not $fileName)
    {
        throw $(Get-PSResourceString -BaseName 'ParameterBinderStrings' -ResourceId 'AmbiguousParameterSet')
    }

    if ($list -and $recurse)
    {
        throw $(Get-PSResourceString -BaseName 'ParameterBinderStrings' -ResourceId 'AmbiguousParameterSet')
    }

    if ($sectionName -and -not $fileName)
    {
        throw $(Get-PSResourceString -BaseName 'ParameterBinderStrings' -ResourceId 'AmbiguousParameterSet')
    }

    if ($list)
    {
        if ($sectionName)
        {
            [xml]$xml = Get-Content $filename
            $rootNode = $xml.get_documentElement()
            $rootNode.sectionSchema | ForEach-Object {
                $nodeObject = $_               
                if ($nodeObject.name.tolower() -eq $sectionName.tolower())
                {                 
                    $nodeObject
                }
            }            
        }
        else
        {
            if ($fileName)
            {
                [xml]$xml = Get-Content $filename
                $rootNode = $xml.get_documentElement()
                $rootNode.sectionSchema | ForEach-Object {
                    $sectionName = $_.name
                    $sectionName
                }          
            }
            else
            {
                Get-ChildItem "$env:windir\system32\inetsrv\config\schema" -filter *.xml | ForEach-Object {
                    $filePath = $_.fullname
                    $filePath
                }
            }
        }   
    }
    else
    {
        if (-not $fileName -and -not $nodeObject) {
            throw $($(Get-PSResourceString -BaseName 'ParameterBinderStrings' -ResourceId 'ParameterArgumentValidationErrorNullNotAllowed') -f $null,'fileName')
        }

        if (-not $nodeObject)
        {
            [xml]$xml = Get-Content $filename
            $rootNode = $xml.get_documentElement()
            $rootNode.sectionSchema | ForEach-Object {
                $nodeObject = $_
                if ((-not $sectionName) -or ($nodeObject.name.tolower() -eq $sectionName.tolower()))
                {
                    Get-WebSchema -nodeObject $_ -filename $fileName -sectionName $nodeObject.name -verbose:$verbose
                }
            }           
        }      
        else
        {
            ("element", "collection", "attribute", "method") | ForEach-Object {
                $type = $_.tostring()
                if ($nodeObject.$type -ne $null)
                {  
                    $nodeObject.$type | ForEach-Object {
                         $leafObject = $_
                         $output = new-object psobject
                         if ($type -eq "collection")
                         {
                             $name = $leafObject.addElement
                             if ($verbose)
                             {
                                 $name = "[name]"
                             }
                         }
                         else
                         {
                             $name = $leafObject.name
                         }                       

                         $ItemXPath = $null
                         if ($verbose)
                         {
                             $ItemXPath = ($sectionName+"//"+$name)
                         }
                         else
                         {
                             $ItemXPath = ($sectionName+"/"+$name)
                         }
                         add-member -in $output noteproperty ItemXPath $ItemXPath
                         add-member -in $output noteproperty Name $name
                         add-member -in $output noteproperty XmlObject $leafObject
                         add-member -in $output noteproperty Type $leafObject.toString()
                         add-member -in $output noteproperty ParentXPath $sectionName
                         $output

                         if ($type -eq "element" -or $type -eq "collection")
                         {
                             Get-WebSchema -nodeObject $_ -filename $fileName -sectionName $ItemXPath -verbose:$verbose
                         }
                    }
                }
            }
        }
    }
}

$global:iis = new-object psobject
(dir "$env:windir\system32\inetsrv\config\schema\*.xml") | sort -Descending | select FullName,Name | foreach {
  $file = $_.Name
  $filepath = $_.FullName
 
  $saved_section = $null
  $sectionName = $null  
  $sectionValue = $null   

  Get-WebSchema -fileName $filePath | where {$_.Type -eq "attribute"} | foreach {
    $sectionPath = $_.ParentXPath
    $attribute = $_.Name

    ##
    ## when a new section is found
    ##
    if ($saved_section -ne $sectionPath) {
 
      if ($sectionName -ne $null) 
      {
        ##
        ## Now that the $sectionvalue is made for a specific config section,
        ## let's add the unique $sectionName noteproperty with $sectionName value onto $iis object
        ##
        add-member -in $iis noteproperty $sectionName $sectionValue
      }

      ##
      ## Let's create a new $sectionValue with assigning a new sectionPath value
      ##
      $sectionValue = $sectionPath

      ##
      ## Let's get an unique $sectionName which was not used before
      ##
      $tokens = $sectionPath.split("/")
      $sectionName = $tokens[$tokens.length-1]

      if ($tokens.length -gt 1 -and $tokens[$tokens.length-1] -eq "add")
      {
        $sectionName = $tokens[$tokens.length-2] + "_" + $tokens[$tokens.length-1]
      }
     
      ##
      ## if existing one has the same section configPath, copy it to the $sectionValue and then remove existing one in order to append
      ##
      if ($iis.$sectionName -ne $null -and $iis.$sectionName -eq $sectionPath)
      {
        $sectionValue = $iis.$sectionName
        $iis = $iis | select * -exclude $sectionName
      }
     
      if ($iis.$sectionName -ne $null)
      {
        $i = 2;
        do
        {
          $temp = $sectionName + $i
          $i = $i + 1
        }
        while ($iis.$temp -ne $null)           
        $sectionName = $temp
      }

      # reset $saved_section variable with the new section path
      $saved_section = $sectionPath
    }

    ##
    ## Let's add all of the attributes as a child noteproperty onto the $sectionValue string object
    ##
    $sectionValue = $sectionValue | add-member -membertype noteproperty -name ("_"+$attribute) -value $attribute -passthru
  }

  if ($sectionName -ne $null)
  {
    ##
    ## Let's process the last $sectionValue after loop statement
    ##
    add-member -in $iis noteproperty $sectionName $sectionValue
  }
}

Developing IIS Native module 2 (Replacing response body with WriteEntityChunkByReference)

$
0
0

Summary:

In the last blog, I tried to explain the big picture for IIS native API. So, next thing is to make a real native module. Because IIS native api is huge, I will introduce one by one with some interesting topics and explain why I was interested in for the specific topic.

In this blog, I decided to make a small program with which I can replace the response body with a specific data so that I can learn how to use the IIS native API for manipulating the response data. As usual, I had to solve some issues and hope to share what I learned while solving the problem.

What I learned:

If you look at the attached code below, you will notice the following two lines, which was my first issue to solve.

//char szBuffer[BUFFERLENGTH];
//char szBuffer2[BUFFERLENGTH];  

Because I did not know what memory should be used to set the FromMemory.pBuffer pointer, I started with a stack memory which is used by local variable and I realize it does not work. I got bunch of 0 values or some garbage data.
And then I realize that IIS API requires the memory should be kept in the life cycle of the request and that's why the stack memory did not work. Also, I realize httpContext has AllocateRequestMemory() method and we can allocate a certain size of memory with using it and the memory is kept during the life cycle of the request. So, I got the answer how to fix the first issue.

And then I wanted to display some non-English string and I realize the non-English string, for example Unicode string, should be encoded in UTF8 so that IE can display the data correctly.

I used WriteEntityChunkByReference() API function to set response body with my own data because we can directly assign my data using the API.

One thing interesting regarding the function is we can set -1 to append the data to the existing response body data.

I used OnGlobalPreBeginRequest event handler here. Please refer to MSDN what the event handler means.  

I also added the line of "pHttpResponse->Clear();" but it does not meaningful in the OnGlobalPreBeginRequest event handler because the response body is actually already empty because the response body is not made yet in that stage.

 

#include

"stdafx.h"
#define _WINSOCKAPI_
#include <httpserv.h>

class MyGlobalModule : public CGlobalModule
{
public:

    GLOBAL_NOTIFICATION_STATUS
    OnGlobalPreBeginRequest(IN IPreBeginRequestProvider * pProvider)
    {
        HRESULT hr = S_OK;
        IHttpContext* pHttpContext = pProvider->GetHttpContext();
        IHttpResponse * pHttpResponse = pHttpContext->GetResponse();

        if (pHttpResponse != NULL)
        {
            HTTP_DATA_CHUNK dataChunk1;
            HTTP_DATA_CHUNK dataChunk2;
           
            pHttpResponse->Clear();

            int BUFFERLENGTH = 256;

            //char szBuffer[BUFFERLENGTH];
            //char szBuffer2[BUFFERLENGTH];   

            char* szBuffer = (char *) pHttpContext->AllocateRequestMemory(BUFFERLENGTH);
            char* szBuffer2 = (char *) pHttpContext->AllocateRequestMemory(BUFFERLENGTH);

            dataChunk1.DataChunkType = HttpDataChunkFromMemory;
            strcpy_s(szBuffer, 255, "Hello world!!!\r\n");

            dataChunk1.FromMemory.pBuffer = (PVOID) szBuffer;
            dataChunk1.FromMemory.BufferLength = (ULONG) strlen(szBuffer);
            hr = pHttpResponse->WriteEntityChunkByReference( &dataChunk1, -1);

            if (FAILED(hr))
            {
                pProvider->SetErrorStatus( hr );               
                return GL_NOTIFICATION_HANDLED;
            }

            dataChunk2.DataChunkType = HttpDataChunkFromMemory;
            wchar_t wstrTest1[] = L"안녕하세요";
            int encodedStrLen = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) wstrTest1, -1, szBuffer2, BUFFERLENGTH, NULL, NULL);

            dataChunk2.FromMemory.pBuffer = (PVOID) szBuffer2;
            dataChunk2.FromMemory.BufferLength = encodedStrLen;
            hr = pHttpResponse->WriteEntityChunkByReference( &dataChunk2, -1);

            if (FAILED(hr))
            {
                pProvider->SetErrorStatus( hr );                
                return GL_NOTIFICATION_HANDLED;
            }
            return GL_NOTIFICATION_HANDLED;
        }

        return GL_NOTIFICATION_CONTINUE;
    }

    VOID Terminate()
    {
        delete this;
    }

    MyGlobalModule()
    {
    }

    ~MyGlobalModule()
    {
    }
};

HRESULT
__stdcall
RegisterModule(
    DWORD dwServerVersion,
    IHttpModuleRegistrationInfo * pModuleInfo,
    IHttpServer * pGlobalInfo
)
{
    UNREFERENCED_PARAMETER( dwServerVersion );
    UNREFERENCED_PARAMETER( pGlobalInfo );

    MyGlobalModule * pGlobalModule = new MyGlobalModule;

    if (NULL == pGlobalModule)
    {
        return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
    }

    return pModuleInfo->SetGlobalNotifications(
        pGlobalModule, GL_PRE_BEGIN_REQUEST );
}

 

How to test the source code:

1. Logon as local administrator's account onto a machine where IIS is installed

2. Create a Visual C++ project of "Class Library" to make a DLL.

3. Copy and paste the above code

4. Right-mouse click the "Source Files" folder and click "Add" context menu and then select "New Item..."

5. Choose "Module-Definition File (.def)" and create a new .def file and paste the following 3 lines (NOTE: the "mod_HelloWorld" was used here because my project is to create the mod_HelloWorld.dll file; you should use the name of the dll file which is created by your project instead of the "mod_HelloWorld"):

LIBRARY "mod_HelloWorld"
EXPORTS
RegisterModule

6. Create a local directory such as c:\privates

7. Compile the project to make the dll file, mod_HelloWorld.dll for example, and copy the dll file onto the newly created local directory

8. Open %windir%\system32\inetsrv\config\applicationhost.config file and add two lines of <add>, one in the globalModules section and the other in the modules section, as the following:
        ...
            <add name="mod_HelloWorld" image="C:\privates\mod_HelloWorld.dll" />
        </globalModules>

        ... 

            <add name="mod_HelloWorld" />
        </modules>
9. Launch IE and send http://localhost request and now you will see the response body is replaced with "Hello world!!! 안녕하세요". (FYI, if the result is displayed with broken characters, the current encoding is not UTF8, which can be fixed by right-mouse-clicking the IE's main page, selecting "Encoding" context menu and choosing the "Unicode (UTF-8)" encoding.

Conclusion:

Now, I hope you feel confident about how to use the WriteEntityChunkByReference API for manipulating the response body and how to handle non English string to make response body with using this simple module.

If you are not clear yet, please try to read the code carefully and try to update the code as you want. I realize the best way to learn programing is to do it by myself without other's help. IIS native API, however, is too huge to catch them easily but you will feel it is actually not that huge eventually. 

I will try to introduce more interesting topic in the next time. 

 

 

 

 

Examples of IIS Powershell cmdlets

$
0
0

Summary:

This document explains how to specify the values of parameter values and how the configuration file is updated by IIS Powershell generic cmdlets such as Get-WebConfiguration and Get-WebConfigurationProperty so that users can use them effectively.

I'd like to inform that the configuration editor of IIS9 has an useful feature to generate IIS Powershell cmdlets. You can use that feature if you want to get the example usage quickly. 

  

  1. Examples how to use parameter values

-PSPATH

COMMAND Examples:  -PSPATH is used to specify the target web object such as server/site/web application/virtual directory and physical directory. The following examples show that there are two equivalent type of PSPATH

 

## Using the path form which is used by MWA and you can specify MACHINE or MACHINE/WEBROOT level as well in this form; The "MACHINE/WEBROOT/APPHOST" is equivalent to "IIS:\", which is another form of PSPATH

$filter = "appSettings"

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

Get-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName

 

## IIS Powershell provider style PSPATh, which starts with "IIS:\"

$pspath = 'IIS:\Sites\Default Web Site\webapplication1'

Get-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName

 

## Even -pspath parameter don't need to be specified if the current directory location is changed to that place

Cd  'IIS:\Sites\Default Web Site\webapplication1'

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

TIP

  1. For server level configurations such as config section which starts with system.applicationhost, we can skip to specify the pspath parameter also

-Filter

COMMAND Examples:  -Filter can be xpath form to specify a specific or multiple  items of IIS config object such as element/collection/attribute; It will be very useful for you to know various xpath style value to enumerate IIS configurations. 

 

## Specify a site element section with xpath style value

$filter = "//sites/site"

$propertyName = "id"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a site element section with full path value

$filter = "system.applicationHost/sites/site"

$propertyName = "id"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Enumerating site (NOTE: the following five xpath examples are equivalent  in IIS config file and shows that you can use wild card value. FYI, "." means a collection item, which can be optional for specifying collection items)

Get-WebConfiguration -filter /system.applicationHost/sites/site

Get-WebConfiguration -filter /system.applicationHost/sites/site/.

Get-WebConfiguration -filter /*/*/site

Get-WebConfiguration -filter //sites/site

Get-WebConfiguration -filter //*/sites/site

 

## Enumerating name attribute of site (NOTE: the following two xpath examples are equivalent)

Get-WebConfiguration -filter /system.applicationHost/sites/site/@name

Get-WebConfiguration -filter //sites/site/@name

Get-WebConfiguration -filter //sites/site/./@name

 

## Specify a certain site node with filtering with multiple attribute values

$filter = "/system.applicationHost/sites/site[@name='Default Web Site' and @id='1']"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain site node with a single attribute value

$filter = "/system.applicationHost/sites/site[@name='Default Web Site']"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain site node with contains() function to say that its attribute "name" should contain a specific string

$filter = "/system.applicationHost/sites/site[contains(@name,'Default')]" 

Get-WebConfigurationProperty -filter $filter -name $propertyName
 

## Specify a certain site node with last() function to say that its attribute "name"  should end with a specific string

$filter = "/system.applicationHost/sites/site[last(@name,'Site')]"

Get-WebConfigurationProperty -filter $filter -name $propertyName
 

## Specify a certain site node with starts-with() function to say that its attribute "name" should start with a specific string

$filter = "/system.applicationHost/sites/site[starts-with(@name,'Default')]"

Get-WebConfigurationProperty -filter $filter -name $propertyName
 

## Specify a certain site node with position() function to say it should be placed at first

$filter = "/system.applicationHost/sites/site[position()=1]"

Get-WebConfigurationProperty -filter $filter -name $propertyName
 

## Specify a certain site node with count() to say that its parent should have only one site node 

$filter = "//*[count(site)=1]/site"

Get-WebConfigurationProperty -filter $filter -name $propertyName
 

## Specify a certain site node with name() to say that the element name should be "site"

$filter = "//*[name()='site']"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain site node with local-name() to say that the element name should be "site"

$filter = "//*[local-name()='site']"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain site node with starts-with() function to say that the element name should start "site"  should end with a specific string

$filter = "//*[starts-with(name(),'site')]"

Get-WebConfigurationProperty -filter $filter -name $propertyName
 

## Specify a certain site node with concat() function to say that the combined string of name and id attributes should be a specific string, "Default Web Site1", which is "Default Web Site" + "1"

$filter = "/system.applicationHost/sites/site[concat(@name, @id)='Default Web Site1']"

Get-WebConfigurationProperty -filter $filter -name $propertyName
 

## Specify a certain node with substring-after() function to say that the node name should contains  a specific string such as "site"

$filter = "//*[substring-after(name(), 'site')]"

Get-WebConfigurationProperty -filter $filter -name $propertyName
 

## Specify a certain node with substring-before() function to say that the node name should contains  a specific string such as "ite"

$filter = "//*[substring-before(name(), 'ite')]"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain node with substring function to say that the node name's substring start 0th with length 2 should be a specific string such as "si"

$filter = "//*[substring(name(),0,2)='si']"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain node with string-length() function to say that the legnth of the node name should be 4

$filter = "//*[string-length(name())=4]"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain node with string-length() function to say that the legnth of the node name should be 4

$filter = "//*[string-length(name())=4]"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain site node with translate() function to say that its name attribute value should be "default web site" if "D" in the original string is replaced with "d", "W" with "w", and "S" with "s" as well

$filter ="/system.applicationHost/sites/site[translate(@name, 'DWS', 'dws')='default web site']"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain site node with compare-string-ordinal() function to say that its name attribute should be "default web site" in comparing case-in-sensitively

$filter ="/system.applicationHost/sites/site[compare-string-ordinal(@name,'default web site',true())=0]"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain site node with compare-string-ordinal() function to say that its name attribute should be "Default Web Site" in comparing case-in-sensitively

$filter ="/system.applicationHost/sites/site[compare-string-ordinal(@name,'Default Web Site',false())=0]"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain site node with compare-string-ordinal() function to say that its name attribute should be "Default Web Site" in comparing case-in-sensitively

$filter ="/system.applicationHost/sites/site[compare-string(@name,'Default Web Site',true())=0]"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Using "and" and "or" for set multiple condition using contains() function

$filter='/system.webServer/handlers[(contains(@accessPolicy, "Script") and contains(@accessPolicy, "Write")) or (contains(@accessPolicy, "Execute") and contains(@accessPolicy, "Write"))]'

Get-WebConfiguration -filter $filter -recurse

 

## following xpath functions are also supported:

Normalize-space(), Boolean(), Not(), Number(), Sum(), Floor(), Ceiling(), Round() and Compare-string()

-Name

COMMAND Examples:  -Name parameter is used by Get-WebConfigurationProperty and it is used to specify not only property name but also collection item

 

## Return attribute object for a specific attribute of "name"

Get-WebConfigurationProperty -filter "/system.applicationHost/sites/site" -name name

 

## Return list of collection objects  using "." or Collection which are special attribute name to specify collection items

Get-WebConfigurationProperty -filter "/system.applicationHost/sites" -name .

Get-WebConfigurationProperty -filter "/system.applicationHost/sites" -name Collection


NOTE: Even though the actual objects returned by the above two commands are exactly the same but the output in display could look different each other.

 

## When collection is used, users can filter out with query in the form of [attributeName=value] 

Get-WebConfigurationProperty -filter "/system.applicationHost/sites" -name Collection[name="Default Web Site"]

 

TIP

  1. The above command can be replaced with using xpath filtering from -filter value as the following:

Get-WebConfigurationProperty -filter "/system.applicationHost/sites/site[@name='DefaultWeb Site']" -name .

  1. Even users can use wild character in the filtering out form, which is not allowed in xpath

Get-WebConfigurationProperty -filter "/system.applicationHost/sites" -name Collection[name="Default*"]

  1. There are special purpose of property name such as Sections and SectionGroups to manage sections

 -Recurse

COMMAND Examples: When -Recurse parameter is used with Get-WebConfiguration or Get-WebConfigurationProperty, users can query recursively not only from the current directory

get-webconfiguration '/system.webServer/handlers[(contains(@accessPolicy, "Script") and contains(@accessPolicy, "Write")) or (contains(@accessPolicy, "Execute") and contains(@accessPolicy, "Write"))]' -recurse

TIP:

  1. You might be confused if you use the -recurse parameter from child level and you got no result. For the example, if you enable  basicAuthentication on Default Web Site and run the following command, you will get empty result. This is because the authentication setting is actually configured in the server level configuration file such as applicationhost.config using location tag of "<location path="Default Web Site">".
     

Get-WebConfigurationProperty '//basicAuthentication' -name enabled   -pspath "MACHINE/WEBROOT/APPHOST/Default

Web Site"  -Recurse

 

In the same situation, if you use the following command with specifying the server level for the pspath parameter, you will get the result.

Get-WebConfigurationProperty '//basicAuthentication' -name enabled   -pspath "MACHINE/WEBROOT/APPHOST"  -Recurse

 

If the authentication setting was configured in the web.config of Default Web Site's root directory after delegating the authentication configuration to site level, both of the above two commands  will work because the actual configuration is now set in the Default Web Site level.

-Value

COMMAND Examples:  When -Value  parameter is used by IIS powershell cmdlet, it usually set with a single string value (NOTE: if the value contains space, it should be quoted with " or ')
 

## The value can be hash table object if it is used to set a collection item

add-webconfiguration '/system.applicationHost/sites/site[@name="Default Web Site"]/bindings'-value @{protocol="http";bindingInformation="*:80:"} -pspath iis:\ 

 

  1. Adding  "file" attribute

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings file="test">    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

$propertyName = "file"

$propertyValue =  "test"

 

Set-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value $propertyValue

 

  1. Removing "file" attribute

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettingsfile="test">    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings/@file"

 

clear-WebConfiguration -pspath $pspath -filter appSettings/@file

 

  1. Locking "file" attribute only

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings lockAttributes="file">    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings/@file"

$lockType = "inclusive"

 

Add-WebConfigurationLock -pspath $pspath -filter $filter -type $lockType

 

  1. Unlock "file" attribute with removing the lockAttributes attribute, which is a specialized attribute

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings lockAttributes="file">    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings/@file"

 

Remove-WebConfigurationLock -pspath $pspath -filter $filter

 

  1. Locking all attributes except "file" attribute with using lockAllAttributesExcept attribute which is a specialized attribute

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings lockAllAttributesExcept="file">    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings/@file"

$lockType = "exclusive"

 

Add-WebConfigurationLock -pspath $pspath -filter $filter -type $lockType

 

  1. Removing  the exclusive lock which is set by lockAllAttributesExcept attribute which is a specialized attribute

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings lockAllAttributesExcept="file">    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

COMMAND Examples: (NOTE: Remove-WebConfigurationLock does not support removing the exclusive lock; As a work-around, we should remove the whole section and copy the previous items)

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

$propertyName = "."

 

$items = (get-webconfigurationproperty -pspath $pspath -filter $filter -name $propertyName).collection

 

Clear-WebConfiguration  -pspath $pspath -filter $filter

 

$items | foreach { Add-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value @{key=$_.key;value=$_.value}  }

 

  1. Adding collection item

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings file="test">    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

$propertyName = "."

$propertyValue =  @{key='ee';value='ee'}

 

Add-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value $propertyValue

 

  1. Modifying property value of collection item

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings file="test">    

      <add key="foo2" value="bar" />

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings/add[@key='foo']"

$propertyName = "key"

$propertyValue =  "foo2"

 

Set-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value $propertyValue

 

  1. Reverting to parent with removing whole config section

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

      <clear/>       

        <add key="foo" value="bar"/>

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

</configuration>

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

 

Clear-WebConfiguration  -pspath $pspath -filter $filter

 

  1. Removing <clear />

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

      <clear/>       

        <add key="foo" value="bar"/>

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

        <add key="foo" value="bar"/>

    </appSettings>

</configuration>

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

$propertyName = "."

 

$items = (get-webconfigurationproperty -pspath $pspath -filter $filter -name $propertyName).collection

 

Clear-WebConfiguration  -pspath $pspath -filter $filter

 

$items | foreach { Add-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value @{key=$_.key;value=$_.value}  }

 

  1. Removing all collection items of the current level only

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <remove key="foo_parent" />

      <add key="foo" value="bar"/>

      <add key="foo2" value="bar2"/>

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

      <remove key="foo_parent" />

    </appSettings>

</configuration>

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

$propertyName = "."

 

$items = (get-webconfigurationproperty -pspath $pspath -filter $filter -name $propertyName).collection  | where {$_.getmetadata("collectionItemFileConfigPath") -eq $pspath }

 

$items | foreach { Remove-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -AtElement @{key=$_.key}  }

 

  1. Remove a specific <remove> item of key value "foo_parent"

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

      <remove key="foo_parent" />

      <remove key="foo_parent2" />

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

      <remove key="foo_parent2" />

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$pspath_parent = 'MACHINE/WEBROOT/APPHOST/Default Web Site'

$filter = "appSettings"

$propertyName = "."

$KeyValue= "foo_parent"

 

$parentItems = (get-webconfigurationproperty -pspath $pspath_parent -filter $filter -name $propertyName).collection

$inheritedItems = (get-webconfigurationproperty -pspath $pspath -filter $filter -name $propertyName).collection  | where {$_.getmetadata("collectionItemFileConfigPath") -ne $pspath }

$localitems = (get-webconfigurationproperty -pspath $pspath -filter $filter -name $propertyName).collection  | where {$_.getmetadata("collectionItemFileConfigPath") -eq $pspath }

 

$removedItems = @{}

$parentItems | foreach {

     $item = $_

     $itemFound = $inheritedItems | where { ($_.key -eq $item.key) -and  ($_.value -eq $item.value) }

     if (($itemFound -eq $null) -and ( $item.key -ne $KeyValue))

     {

       $removedItems.add($item.key, $item.value)

     }

}

 

Clear-WebConfiguration  -pspath $pspath -filter $filter

 

$localitems | foreach { Add-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value @{key=$_.key;value=$_.value}  }

 

$removedItems.Keys | foreach { Remove-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -AtElement @{key=$_}  }

 

  1. Remove all collection items including items inherited from parents

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

     <add key="foo" value="bar"/>

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

    <clear/>        

    </appSettings>

</configuration>

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

$propertyName = "."


Rem
ove-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName

 

  1. Remove "foo_parent" collection item which is inherited from parent level)

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

     <add key="foo" value="bar"/>

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

       <remove key="foo_parent" />

        <add key="foo" value="bar"/>

    </appSettings>

</configuration>

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

$propertyName = "."

$propertyValue =  "foo_parent"

 

Remove-WebConfigurationProperty  -pspath $pspath -filter $filter -name $propertyName -AtElement @{key=$propertyValue}

 

  1. Remove "foo" collection item for a specific file such as default.aspx which is placed at the current directory

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar"/>

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

    <location path="default.aspx">

        <appSettings>

            <remove key="foo" />

        </appSettings>

    </location>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

$propertyName = "."

$propertyValue =  "foo"

$locationPath =  "default.aspx"

 

Remove-WebConfigurationProperty  -pspath $pspath -filter $filter -name $propertyName -AtElement @{key=$propertyValue} -location $locationPath

 

  1. Reverting to parent for the default.aspx location

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

    <location path="default.aspx">

        <appSettings>

            <remove key="foo" />

        </appSettings>

    </location>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

    <location path="default.aspx">

    </location>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

$propertyName = "."

$propertyValue =  "foo"

$locationPath =  "default.aspx"

 

clear-webconfiguration  -pspath $pspath -filter $filter -name $propertyName -AtElement @{key=$propertyValue} -location $locationPath

 

  1. Locking collection item

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings file="test">    

      <add key="foo" value="bar"lockItem="true"/>

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings/add[@key='foo']"

$lockType = "general"

 

Add-WebConfigurationLock -pspath $pspath -filter "appSettings/add[@key='foo']" -type $lockType

 

  1. Unlocking collection item

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar"lockItem="true"/>

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings file="test">    

      <add key="foo" value="bar"/>

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings/add[@key='foo']"

 

Remove-WebConfigurationLock -pspath $pspath  -filter $filter

 

  1. Set machine level with specifying framework version of v2.0, which is different to the default value -> This is only applicable for Windows 2012

FROM: for the root web.config file of .Net v2.0

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT'

$filter = "appSettings"

$propertyName = "file"

$propertyValue =  "test"

$clrVersion = "v2.0"

 

Set-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value $propertyValue -clr $clrVersion

 

  1. Locking item from section level

FROM: for the applicationhost.config file

...

</configuration>

 

TO:

...

    <appSettings lockItem="true" />

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST'

$filter = "appSettings"

$type="general"

 

Add-WebConfigurationLock-pspath $pspath -filter $filter

 

  1. Remove section level lock

FROM: for the applicationhost.config file

...

    <appSettings lockItem="true" />

</configuration>

 

TO:

    <appSettings/>

</configuration>

...

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST'

$filter = "appSettings"

 

Remove-WebConfigurationLock-pspath $pspath -filter $filter

 

  1. Add a new section group

FROM: for the applicationhost.config file

...

    </configSections>

...

 

TO:

        <sectionGroup name="MySectionGroup" />

    </configSections>

...

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST'

$filter = "/"

$propertyName = "sectionGroups"

$propertyValue =  "MySectionGroup"

 

Add-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value $propertyValue

 

  1. Delete a section group

FROM: for the applicationhost.config file

...

        <section name="MySection" />

    </configSections>

...

 

TO:

    </configSections>

...

 

COMMAND Examples:

 

## FYI, This is to show how to get the section object at root level

get-WebConfigurationProperty -pspath iis:\ -filter / -name sectionGroups["MySectionGroup"]

 

## Delete the section group

Remove-WebConfigurationProperty -pspath iis:\ -filter "/" -name sectionGroups["MySectionGroup"]

 

  1. Add a new section

FROM: for the applicationhost.config file

...

    </configSections>

...

 

TO:

        <section name="MySection" />

    </configSections>

...

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST'

$filter = "/"

$propertyName = "sections"

$propertyValue =  "MySection"

 

Add-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value $propertyValue

 

  1. Delete a section

FROM: for the applicationhost.config file

...

        <section name="MySection" />

    </configSections>

...

 

TO:

    </configSections>

...

 

COMMAND Examples:

 

## FYI, This is to show how to get the section object at root level

get-WebConfigurationProperty -pspath iis:\ -filter / -name sections["MySection"]

 

## Delete the section

Remove-WebConfigurationProperty -pspath iis:\ -filter "/" -name sections["MySection"]

 

  1. Add a new section under a specific section group

FROM: for the applicationhost.config file

...

        <sectionGroup name="MySectionGroup" />

    </configSections>

...

 

TO:

        <sectionGroup name="MySectionGroup">

             <section name="MyChildSection" />

        </sectionGroup>           

    </configSections>

...

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST'

$filter = "/MySectionGroup"

$propertyName = "sections"

$propertyValue =  "MyChildSection"

 

Add-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value $propertyValue

 

  1. Delete a section under a specific section group

FROM: for the applicationhost.config file

...

        <sectionGroup name="MySectionGroup">

             <section name="MyChildSection" />

        </sectionGroup>           

    </configSections>

...

 

TO:

        <sectionGroup name="MySectionGroup" />

    </configSections>

...

 

COMMAND Examples:

 

## FYI, This is to show how to get the section object under the specific section group

get-WebConfigurationProperty -pspath iis:\ -filter /MySectionGroup -name sections["MyChildSection"]

 

## Delete the section

Remove-WebConfigurationProperty -pspath iis:\ -filter "/MySectionGroup" -name sections["MyChildSection"]

 

  1. Configure "Deny" for OverrideModeDefault attribute of a specific section

FROM: for the applicationhost.config file

...

        <sectionGroup name="system.webServer">

            <section name="asp" overrideModeDefault="Deny" />

...

 

TO:

        <sectionGroup name="system.webServer">

            <section name="asp" overrideModeDefault="Allow" />

...

 

COMMAND Examples:

 

Set-WebConfigurationProperty -filter /system.webServer -name 'sections["asp"].OverrideModeDefault' -value Allow -pspath iis:\

 

 

Developing IIS Native module

$
0
0

I have started to learn IIS Native API (C++) and hope to share what I have learned. This blog is targeting for beginner programmers who want to develope IIS native module in C++ for the first time.

What I will cover here
  • Understanding Global Module/Module/Handler
  • Quick reference of IIS Native API 
  • IIS Core system 

Understanding Global Module/Module/Handler

In order to learn IIS native API, I tried to create a small module with various sample codes and found some cases of not working. In the explanation of the popular example module, I had learned that I needed to register the module onto both <globalModules> and <modules> section. And it worked with no question. 

  • TIP
    • My first module did not work because I complied the module as x86 version and wanted to make it run on amd64 bit machine. The problem was solved with compiling the module as 64 bit compilation)
    • Another mistake happened when I used the full path of my module dll file which is created by Visual Studio without access permission. I had to give the access permission for the users group for the directory to solve the error such as "The Module DLL c:\work\IISNativeModule\Debug\MyModule.dll failed to load. The data is the error." which was shown in the event viewer.

My first module was to subscribe a single global level event such as GL_PRE_BEGIN_REQUEST and it worked in that way. And soon I realized the module works even though I removed the line of module from the <modules> section and I realized that if the module needs to subscribe only global level events, we don't need to register module onto <modules> section. This is how I learned the difference between module and global module in configuration wide.

I also tried to create another module which subscribes a single request level event such as RQ_EXECUTE_REQUEST_HANDLER. But this time, the module did not work even though I registered in the both <globalModules> and <modules> section.
I realized that actually I had made a handler module even though I thought I was making an ordinary module and I had to configure addional thing. Handler module is a special module which subscribes only the RQ_EXECUTE_REQUEST_HANDLER event. So, so the problem had to be solved by registering the module to <handlers> section.

But, I ran into another problem after I put my module, "TestModule", at the end of the value of modules attribute like this.

            <add name="StaticFile" path="*" verb="*" modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule, TestModule" resourceType="Either" requireAccess="Read" />

When I sent a request but the module was not invoked. And the problem was solved by changing the order of the module names like this.

            <add name="StaticFile" path="*" verb="*" modules=" TestModule ,StaticFileModule,DefaultDocumentModule,DirectoryListingModule" resourceType="Either" requireAccess="Read" />

That means, if there are multiple modules in a single handler item such as the above case, the previous modules can determine to make the next module run or not. And that's why my module was not picked up.

If you want to know more about this topic, refer to http://blogs.msdn.com/b/tmarq/archive/2007/08/30/iis-7-0-asp-net-pipelines-modules-handlers-and-preconditions.aspx.


Quick reference of IIS Native API

While I read MSDN, the number of classes/interfaces/struct/constants made me confused and overwhelmed. So, to get rid of the complexity, I tried to summarize the relationship between each interfaces and event handlers. After that, I felt it was not that complicated actually. Here is my version of summurized set of API, which I attached here for you to find the overal view of whole API sets.

1) Classes which are implemented in global or regular module (or handler module)

  • CGlobalModule, which is for global module
  • IHttpModuleFactory, which is a class factory of regular module
  • CHttpModule, which is for regular module

2) The order of creating the class objects

  • All objects should be created when RegisterModule() function, which is the unique exported DLL function of the module
  • CGlobalModule object is created at the heap memory and then its pointer is passed to IIS worker process by calling SetRequestNotifications() function
  • IHttpModuleFactory object is also created at the heap memory and then its pointer is passed to IIS worker process by calling SetGlobalNotifications() function
  • HttpModule object is created when IHttpModuleFactory object's GetHttpModule() function is called by IIS worker process
  • NOTE:
  • a. When GetHttpModule() is called, which happens for once for every request, we should create the HttpModule object every time and the object should be deleted if it was created in the heap memory when each request life cycle is finished
  • b. If you want to create a the module in heap, not stack memory, you can use IModuleAllocator interface to allocate memory of request pool
  • c. CGlobalModule event handler functions

3) Handler function name ant its event provider type

  • OnGlobalApplicationPreload
    • IGlobalApplicationPreloadProvider
  • OnGlobalApplicationResolveModules
    • IHttpApplicationResolveModulesProvider
  • OnGlobalApplicationStart
    • IHttpApplicationStartProvider
  • OnGlobalApplicationStop
    • IHttpApplicationStopProvider
  • OnGlobalCacheCleanup
    • void
  • OnGlobalCacheOperation
    • ICacheProvider
  • OnGlobalConfigurationChange
    • IGlobalConfigurationChangeProvider
  • OnGlobalCustomNotification
    • ICustomNotificationProvider
  • OnGlobalFileChange
    • IGlobalFileChangeProvider
  • OnGlobalHealthCheck
    • void
  • OnGlobalPreBeginRequest
    • IPreBeginRequestProvider
  • OnGlobalRSCAQuery
    • IGlobalRSCAQueryProvider
  • OnGlobalStopListening
    • IGlobalStopListeningProvider
  • OnGlobalThreadCleanup
    • IGlobalThreadCleanupProvider
  • OnGlobalTraceEvent
    • IGlobalTraceEventProvider
  • OnGlobalTerminate
    • void
  • Return value which are applied to all event handlers
    • GL_NOTIFICATION_CONTINUE
    • GL_NOTIFICATION_HANDLED, which indicates to stop IIS pipeline

4) CHttpModule event handler functions

  • Handler function name ant its event provider type
    • OnAcquireRequestState
      • OnPostAcquireRequestState
    • OnAsyncCompletion
    • OnAuthenticateRequest  (IAuthenticationProvider)
      • OnPostAuthenticateRequest
    • OnAuthorizeRequest
      • OnPostAuthorizeRequest
    • OnBeginRequest
      • OnPostBeginRequest
        • OnPostEndRequest
    • OnCustomRequestNotification (ICustomNotificationProvider)
    • OnEndRequest
    • OnExecuteRequestHandler
      • OnPostExecuteRequestHandler
    • OnLogRequest
      • OnPostLogRequest
    • OnMapPath (IMapPathProvider)
    • OnMapRequestHandler
      • OnPostMapRequest
    • OnPreExecuteRequestHandler
      • OnPostPreExecuteRequestHandler
    • OnReleaseRequestState
      • OnPostReleaseRequestState
    • OnResolveReuqestCache
      • OnPostResolveRequestCache
    • OnUpdateRequestCache
      • OnPostUpdateRequestCache
    • OnReadEntity (IReadEntityProvider)
    • OnSendResponse (ISendResponseProvider)
  • Return value which are applied to all event handlers
    • RQ_NOTIFICATION_CONTINUE
    • RQ_NOTIFICATION_FINISH, which indicates to stop IIS pipeline from request level
    • RQ_NOTIFICATION_PENDING, which indicates to stop IIS pipeline temporarily while module's executing its own task asynchronously.  There are two ways to do this such as using IHttpContext::ExecuteRequest and OnAyncCompletion() and IHttpContext::PostCompletion()

5) IHttpEventProvider and derived interfaces

  • IHttpEventProvider
    • IAuthenticationProvider
    • ICacheProvider
      • IHttpCacheKey  <== GetCacheKey()
        • IFileKey
        • IHttpTokenKey
        • IUriKey
      • IHttpCacheSpecificData  <== GetCacheRecord()
        • IHttpTokenEntry
    • ICustomNotificationProvider
    • IGlobalApplicationPreloadProvider
      • IGlobalApplicationPreloadProvider2
    • IGlobalConfigurationChangeProvider
    • IGlobalFileChangeProvider
      • IHttpFileMonitor  <== GetFileMonitor()
    • IGlobalRscaQueryProvider
    • IGlobalStopListeningProvider
    • IGlobalThreadCleanupProvider
    • IGlobalTraceEventProvider
    • IHttpApplicationProvider
    • IHttpApplicationResolveModulesProvider
    • IPreBeginRequestProvider
    • ISendResponseProvider
    • IMapHandlerProvider
    • IMapPathProvider
    • IReadEntityProvider
    • IHttpApplicationStartProvider

6) Relationship between Interfaces

  • IHttpCompletionInfo  <== CHttpModule::OnAsyncCompletion()
    • IHttpCompletionInfo2
  • IHttpContext
    •  IHttpApplication  <== GetApplication()
      • IHttpApplication2
    • IHttpConnection <== GetConnection()
    • IHttpFileInfo   <== GetFileInfo()
    • IMetadataInfo   <= GetMetadata()
      • IReferencedMetadataInfo
    • IHttpModuleContextContainer  <== GetModuleContextContainer()
      • IHttpStoredContext <== GetModuleContext()
        • IWebSocketContext
        • IHttpConnectionStoredContext
      • IDispensedHttpModuleContextContainer
    • IHttpSite  <== GetSite()
    • IHttpUser  <== GetUser()
    • IHttpTraceContext  <== GetTraceContext()
    • IHttpUrlInfo  <== GetUrlInfo()
    • IHttpResponse  <== GetRespons()
      • IHttpCachePolicy  <== GetCachePolicy()
        • IHttpCachePolicy2
      • IHttpResponse2
    • IHttpRequest <== GetRequest()
      • IHttpRequest2
        • IHttpRequest3
    • IScriptMapInfo <== GetScriptMap()
    • IHttpContext2
      • IHttpContext3
        • INamedContextContainer <== GetNamedContextContainer()
  • IHttpModuleRegistrationInfo
    • IHttpModuleFactory ==> SetRequestNotifications()
      • IModuleAllocator <== GetHttpModule()
  • IHttpServer <== RegisterModule
    • IHttpServer2
    • IHttpPerfCounterInfo  <== GetPerfCounterInfo()   (IHttpSite::GetPerfCounterInfo() has the function)

IIS Core system

While summarizing the whole IIS native API, there are another confusing thing regarding the return value of the event handler.
At first, I imagined there should be only two such as "Continue" and "Finish", one for succes and the other for failure. But I realized that there was one more return value such as "RQ_NOTIFICATION_PENDING".
MSDN explains that it is used for asynchronous task handling but it was not that helpful because I didn't know how IIS and module should work together. 
So before understanding that, I had to make some curiosity about how IIS actually works and finally I managed to make some big ficture of IIS internal system and even made a very simple program which explains the relationship between the important Interface classes and our module classes which we should develop. The below attached code is compliable code in any C++ compiler. I just wanted to create my own simplified version of important IIS native API interfaces and classes. The purpose of the small program was to simulate how IIS handles the request and call IIS modules in its module pipeline, supposing there is only one module. Actual life cycle of request would be like as the following steps though:

  • IIS reads the applicationhost.config and prepare a list data structure of module objects in order to make all of the modules work for the request; Each module object implement event handler functions.
  • Now, IIS is ready and OS kernel system such as HTTP receive a request from wire and passes the request object to IIS
  • And then IIS creates a HttpContext object and copy the pointer of the request object to the HttpContext object, which will be used by modules
  • IIS creates a IISEventHandler object and the pointer of the HttpContext object is also copied to it
  • IIS call the event handler function of each module with the parameter of the IISEventHandler object
  • Each module participate in manipulating the request object and response body in its event handler functions
  • Once all modules finish the event handler functions, IIS give the response body to OS kernel system such as HTTP service

Summary

Today, I tried to review what I learned while trying the sample example codes of http://msdn.microsoft.com/en-us/library/aa347664(v=vs.90).aspx (IIS Native-Code Extensibility API Reference).
In the next time, I will write my own module to experiment more and share about that.

Source code of IIS and module simulation

#include "stdafx.h"
#include <iostream>
using namespace std;

class IHttpContext
{
public:
 virtual void SetHttpRequest(int newValue) = 0; 
};

class IHttpEventProvider
{
public: 
 virtual IHttpContext* GetHttpContext() = 0; 
};

class HttpContext : IHttpEventProvider, IHttpContext
{
private:
 int* _pHttpRequest; 

public:
 HttpContext(int* pHttpRequest) : _pHttpRequest(pHttpRequest)
 {  
 }

 void SetHttpRequest(int newValue)
 {
  *_pHttpRequest = newValue;
 }

 IHttpContext* GetHttpContext()
 {
  return this;
 }
};

class HttpEventProvider: IHttpEventProvider
{
private:
 IHttpContext* _pHttpContext;

public:
 HttpEventProvider(IHttpContext* pHttpContext) : _pHttpContext(pHttpContext)
 {
 }
 
 virtual IHttpContext* GetHttpContext()
 {
  return _pHttpContext;
 }
};

class IModule
{
public:
 virtual void OnBeginRequest(IHttpEventProvider* provider) = 0; 
};

class Module : IModule
{
public:  
 void OnBeginRequest(IHttpEventProvider* pHttpEventProvider)
 { 
  IHttpContext* pHttpContext = pHttpEventProvider->GetHttpContext();
  pHttpContext->SetHttpRequest(3);  
 }
};

int _tmain(int argc, _TCHAR* argv[])
{
  // Step 1.
 // let's suppose httpRequest object is integer value and was created in the beginning.
 // In actual world, the request object is created by http sys service for every request
 int httpRequest = 0; 
 cout << "Original Request: " << httpRequest << endl;

 // Step 2.
 // Now, IIS create the module object here to process the request.
 //In the actual world, it was done by IIS's calling the IHttpModuleFactory::GetModule() method in each module .dll file.
 Module* pModule = new Module(); 

 // Step3.
 // After creating module object, IIS create HttpContext object with copying the httpRequest object inside it.
 HttpContext* pHttpContext = new HttpContext(&httpRequest);

 // Step4
 // And then, IIS creates httpEventProvider object, which will be used by the parameter object of the event handler function which is implemented in each module .dll file
 // As you can see here, the HttpContext object information copied to httpEventProvider object so that event handler can access the httpContext object
 HttpEventProvider httpEventProvider((IHttpContext*) pHttpContext);

 // Step5
 // IIS creates state machine which invokes each deterministic request level events handler which is implemented in each module .dll file.
 // In actual world, there are global level event and non-deterministic request level events and they are fired outside of this state machine.
 IModule* pIModule;
 pIModule = (IModule*) pModule;  
 pIModule->OnBeginRequest((IHttpEventProvider *) pHttpContext);

 // Step6
 // Now the state machine is finished and then response object is passed to the http sys service and it transfer it to the client which started the httpRequest.
 cout << "Modified request by module: " << httpRequest << endl;
 
 // Step7
 // After all of the request is finished, the httpContext and module object is deleted to clean up
 delete pModule;
 delete pHttpContext;

 // In actual world, the event handler function can be implemented to support to handle asyncronous tasks but it wasn't explained here. I will explain it later.
 return 0;
}

IIS Powershell: Getting config section names and attributes names dynamically

$
0
0

IIS Powershell provider cmdlets require the config section path for the -filter parameter and the attribute names while getting/setting attribute value.

But it is not easy to memorize the full configuration path or attribute names for each config section.

So, I have created a utility method and a useful variable, such as $iis, and I put the full source code below so that you can customize if you want.

How to use this tool.

  1. Start powershell.exe
  2. Copy the below code and paste onto the powershell window to register the one utility function, Get-WebSchema, and to create a powershell variable, $iis with using the utility function
  3. Try to run the Example Scenario 6~9 and you will see how you can use this tool with the IIS Powershell cmdlets. (NOTE: you will know you can use the auto-tab funcationality while using the $iis variable, which is what I told about getting config section names and attribute names dynamically as the following example:

    # Ex.) without using $iis variable; users should know the full config path and attribute name
    >> PS C:\Windows\system32> Get-WebConfigurationProperty -filter /system.webServer/security/authentication/basicAuthentication -name enabled

    # Ex.) using $iis variable; users can use the auto-tab to get the config section name string using $iis
    >> Get-WebConfigurationProperty -filter $iis.basicAuthentication -name $iis.basicAuthentication._enabled

####  Copy and paste from here!!!
#
#     -------------------------- EXAMPLE 1 --------------------------
#     C:\> Get-WebSchema -list
#     This command retrieves the list of schema files that are available.
#
#     -------------------------- EXAMPLE 2 --------------------------
#     C:\> Get-WebSchema -list -fileName "$env:windir\system32\inetsrv\config\schema\IIS_schema.xml"
#     This command retrieves the list of sections that are available for IIS_Schema.xml file.
#
#     -------------------------- EXAMPLE 3 --------------------------
#     C:\> Get-WebSchema -list -fileName "$env:windir\system32\inetsrv\config\schema\IIS_schema.xml" -sectionName system.webServer/asp
#     This command retrieves an xml node object for the asp section in Iis_Schema.xml file.
#
#     -------------------------- EXAMPLE 4 --------------------------
#     C:\> Get-WebSchema -fileName "$env:windir\system32\inetsrv\config\schema\IIS_schema.xml" -sectionName system.webServer/asp
#     This command list all config information (Ie. attribute/method/element/collection) of the asp section
#
#     -------------------------- EXAMPLE 5 --------------------------
#     C:\> Get-WebSchema -fileName "$env:windir\system32\inetsrv\config\schema\IIS_schema.xml"
#     This command list all config information (Ie. attribute/method/element/collection) of the IIS_Schema file
#
#     -------------------------- EXAMPLE 6 --------------------------
#     C:\> $iis
#     This command will dump all available config sections
#
#     -------------------------- EXAMPLE 7 --------------------------
#     C:\> $iis.site
#     This command will return string value of the full config path such as system.applicationHost/sites/site
#
#     -------------------------- EXAMPLE 8 --------------------------
#     C:\> $iis.appSettings._file
#     This command will return string value of the attribute name, such as "file", of the appSettings config section.
#     (NOTE: for quick find attribute name, I put "_" string at the beginning of attribute name.
#     For the example, $iis.appSettings._<TAB> will show $iis.appSettings._file.

function global:Get-WebSchema()
{
    param(
        [string]$fileName=$null,
        [string]$sectionName=$null,
        [object]$nodeObject=$null,
        [switch]$list,
        [switch]$verbose
    )

    if ($list -and $sectionName -and -not $fileName)
    {
        throw $(Get-PSResourceString -BaseName 'ParameterBinderStrings' -ResourceId 'AmbiguousParameterSet')
    }

    if ($list -and $recurse)
    {
        throw $(Get-PSResourceString -BaseName 'ParameterBinderStrings' -ResourceId 'AmbiguousParameterSet')
    }

    if ($sectionName -and -not $fileName)
    {
        throw $(Get-PSResourceString -BaseName 'ParameterBinderStrings' -ResourceId 'AmbiguousParameterSet')
    }

    if ($list)
    {
        if ($sectionName)
        {
            [xml]$xml = Get-Content $filename
            $rootNode = $xml.get_documentElement()
            $rootNode.sectionSchema | ForEach-Object {
                $nodeObject = $_               
                if ($nodeObject.name.tolower() -eq $sectionName.tolower())
                {                 
                    $nodeObject
                }
            }            
        }
        else
        {
            if ($fileName)
            {
                [xml]$xml = Get-Content $filename
                $rootNode = $xml.get_documentElement()
                $rootNode.sectionSchema | ForEach-Object {
                    $sectionName = $_.name
                    $sectionName
                }          
            }
            else
            {
                Get-ChildItem "$env:windir\system32\inetsrv\config\schema" -filter *.xml | ForEach-Object {
                    $filePath = $_.fullname
                    $filePath
                }
            }
        }   
    }
    else
    {
        if (-not $fileName -and -not $nodeObject) {
            throw $($(Get-PSResourceString -BaseName 'ParameterBinderStrings' -ResourceId 'ParameterArgumentValidationErrorNullNotAllowed') -f $null,'fileName')
        }

        if (-not $nodeObject)
        {
            [xml]$xml = Get-Content $filename
            $rootNode = $xml.get_documentElement()
            $rootNode.sectionSchema | ForEach-Object {
                $nodeObject = $_
                if ((-not $sectionName) -or ($nodeObject.name.tolower() -eq $sectionName.tolower()))
                {
                    Get-WebSchema -nodeObject $_ -filename $fileName -sectionName $nodeObject.name -verbose:$verbose
                }
            }           
        }      
        else
        {
            ("element", "collection", "attribute", "method") | ForEach-Object {
                $type = $_.tostring()
                if ($nodeObject.$type -ne $null)
                {  
                    $nodeObject.$type | ForEach-Object {
                         $leafObject = $_
                         $output = new-object psobject
                         if ($type -eq "collection")
                         {
                             $name = $leafObject.addElement
                             if ($verbose)
                             {
                                 $name = "[name]"
                             }
                         }
                         else
                         {
                             $name = $leafObject.name
                         }                       

                         $ItemXPath = $null
                         if ($verbose)
                         {
                             $ItemXPath = ($sectionName+"//"+$name)
                         }
                         else
                         {
                             $ItemXPath = ($sectionName+"/"+$name)
                         }
                         add-member -in $output noteproperty ItemXPath $ItemXPath
                         add-member -in $output noteproperty Name $name
                         add-member -in $output noteproperty XmlObject $leafObject
                         add-member -in $output noteproperty Type $leafObject.toString()
                         add-member -in $output noteproperty ParentXPath $sectionName
                         $output

                         if ($type -eq "element" -or $type -eq "collection")
                         {
                             Get-WebSchema -nodeObject $_ -filename $fileName -sectionName $ItemXPath -verbose:$verbose
                         }
                    }
                }
            }
        }
    }
}

$global:iis = new-object psobject
(dir "$env:windir\system32\inetsrv\config\schema\*.xml") | sort -Descending | select FullName,Name | foreach {
  $file = $_.Name
  $filepath = $_.FullName
 
  $saved_section = $null
  $sectionName = $null  
  $sectionValue = $null   

  Get-WebSchema -fileName $filePath | where {$_.Type -eq "attribute"} | foreach {
    $sectionPath = $_.ParentXPath
    $attribute = $_.Name

    ##
    ## when a new section is found
    ##
    if ($saved_section -ne $sectionPath) {
 
      if ($sectionName -ne $null) 
      {
        ##
        ## Now that the $sectionvalue is made for a specific config section,
        ## let's add the unique $sectionName noteproperty with $sectionName value onto $iis object
        ##
        add-member -in $iis noteproperty $sectionName $sectionValue
      }

      ##
      ## Let's create a new $sectionValue with assigning a new sectionPath value
      ##
      $sectionValue = $sectionPath

      ##
      ## Let's get an unique $sectionName which was not used before
      ##
      $tokens = $sectionPath.split("/")
      $sectionName = $tokens[$tokens.length-1]

      if ($tokens.length -gt 1 -and $tokens[$tokens.length-1] -eq "add")
      {
        $sectionName = $tokens[$tokens.length-2] + "_" + $tokens[$tokens.length-1]
      }
     
      ##
      ## if existing one has the same section configPath, copy it to the $sectionValue and then remove existing one in order to append
      ##
      if ($iis.$sectionName -ne $null -and $iis.$sectionName -eq $sectionPath)
      {
        $sectionValue = $iis.$sectionName
        $iis = $iis | select * -exclude $sectionName
      }
     
      if ($iis.$sectionName -ne $null)
      {
        $i = 2;
        do
        {
          $temp = $sectionName + $i
          $i = $i + 1
        }
        while ($iis.$temp -ne $null)           
        $sectionName = $temp
      }

      # reset $saved_section variable with the new section path
      $saved_section = $sectionPath
    }

    ##
    ## Let's add all of the attributes as a child noteproperty onto the $sectionValue string object
    ##
    $sectionValue = $sectionValue | add-member -membertype noteproperty -name ("_"+$attribute) -value $attribute -passthru
  }

  if ($sectionName -ne $null)
  {
    ##
    ## Let's process the last $sectionValue after loop statement
    ##
    add-member -in $iis noteproperty $sectionName $sectionValue
  }
}

Developing IIS Native module 2 (Replacing response body with WriteEntityChunkByReference)

$
0
0

Summary:

In the last blog, I tried to explain the big picture for IIS native API. So, next thing is to make a real native module. Because IIS native api is huge, I will introduce one by one with some interesting topics and explain why I was interested in for the specific topic.

In this blog, I decided to make a small program with which I can replace the response body with a specific data so that I can learn how to use the IIS native API for manipulating the response data. As usual, I had to solve some issues and hope to share what I learned while solving the problem.

What I learned:

If you look at the attached code below, you will notice the following two lines, which was my first issue to solve.

//char szBuffer[BUFFERLENGTH];
//char szBuffer2[BUFFERLENGTH];  

Because I did not know what memory should be used to set the FromMemory.pBuffer pointer, I started with a stack memory which is used by local variable and I realize it does not work. I got bunch of 0 values or some garbage data.
And then I realize that IIS API requires the memory should be kept in the life cycle of the request and that's why the stack memory did not work. Also, I realize httpContext has AllocateRequestMemory() method and we can allocate a certain size of memory with using it and the memory is kept during the life cycle of the request. So, I got the answer how to fix the first issue.

And then I wanted to display some non-English string and I realize the non-English string, for example Unicode string, should be encoded in UTF8 so that IE can display the data correctly.

I used WriteEntityChunkByReference() API function to set response body with my own data because we can directly assign my data using the API.

One thing interesting regarding the function is we can set -1 to append the data to the existing response body data.

I used OnGlobalPreBeginRequest event handler here. Please refer to MSDN what the event handler means.  

I also added the line of "pHttpResponse->Clear();" but it does not meaningful in the OnGlobalPreBeginRequest event handler because the response body is actually already empty because the response body is not made yet in that stage.

 

#include

"stdafx.h"
#define _WINSOCKAPI_
#include <httpserv.h>

class MyGlobalModule : public CGlobalModule
{
public:

    GLOBAL_NOTIFICATION_STATUS
    OnGlobalPreBeginRequest(IN IPreBeginRequestProvider * pProvider)
    {
        HRESULT hr = S_OK;
        IHttpContext* pHttpContext = pProvider->GetHttpContext();
        IHttpResponse * pHttpResponse = pHttpContext->GetResponse();

        if (pHttpResponse != NULL)
        {
            HTTP_DATA_CHUNK dataChunk1;
            HTTP_DATA_CHUNK dataChunk2;
           
            pHttpResponse->Clear();

            int BUFFERLENGTH = 256;

            //char szBuffer[BUFFERLENGTH];
            //char szBuffer2[BUFFERLENGTH];   

            char* szBuffer = (char *) pHttpContext->AllocateRequestMemory(BUFFERLENGTH);
            char* szBuffer2 = (char *) pHttpContext->AllocateRequestMemory(BUFFERLENGTH);

            dataChunk1.DataChunkType = HttpDataChunkFromMemory;
            strcpy_s(szBuffer, 255, "Hello world!!!\r\n");

            dataChunk1.FromMemory.pBuffer = (PVOID) szBuffer;
            dataChunk1.FromMemory.BufferLength = (ULONG) strlen(szBuffer);
            hr = pHttpResponse->WriteEntityChunkByReference( &dataChunk1, -1);

            if (FAILED(hr))
            {
                pProvider->SetErrorStatus( hr );               
                return GL_NOTIFICATION_HANDLED;
            }

            dataChunk2.DataChunkType = HttpDataChunkFromMemory;
            wchar_t wstrTest1[] = L"안녕하세요";
            int encodedStrLen = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) wstrTest1, -1, szBuffer2, BUFFERLENGTH, NULL, NULL);

            dataChunk2.FromMemory.pBuffer = (PVOID) szBuffer2;
            dataChunk2.FromMemory.BufferLength = encodedStrLen;
            hr = pHttpResponse->WriteEntityChunkByReference( &dataChunk2, -1);

            if (FAILED(hr))
            {
                pProvider->SetErrorStatus( hr );                
                return GL_NOTIFICATION_HANDLED;
            }
            return GL_NOTIFICATION_HANDLED;
        }

        return GL_NOTIFICATION_CONTINUE;
    }

    VOID Terminate()
    {
        delete this;
    }

    MyGlobalModule()
    {
    }

    ~MyGlobalModule()
    {
    }
};

HRESULT
__stdcall
RegisterModule(
    DWORD dwServerVersion,
    IHttpModuleRegistrationInfo * pModuleInfo,
    IHttpServer * pGlobalInfo
)
{
    UNREFERENCED_PARAMETER( dwServerVersion );
    UNREFERENCED_PARAMETER( pGlobalInfo );

    MyGlobalModule * pGlobalModule = new MyGlobalModule;

    if (NULL == pGlobalModule)
    {
        return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
    }

    return pModuleInfo->SetGlobalNotifications(
        pGlobalModule, GL_PRE_BEGIN_REQUEST );
}

 

How to test the source code:

1. Logon as local administrator's account onto a machine where IIS is installed

2. Create a Visual C++ project of "Class Library" to make a DLL.

3. Copy and paste the above code

4. Right-mouse click the "Source Files" folder and click "Add" context menu and then select "New Item..."

5. Choose "Module-Definition File (.def)" and create a new .def file and paste the following 3 lines (NOTE: the "mod_HelloWorld" was used here because my project is to create the mod_HelloWorld.dll file; you should use the name of the dll file which is created by your project instead of the "mod_HelloWorld"):

LIBRARY "mod_HelloWorld"
EXPORTS
RegisterModule

6. Create a local directory such as c:\privates

7. Compile the project to make the dll file, mod_HelloWorld.dll for example, and copy the dll file onto the newly created local directory

8. Open %windir%\system32\inetsrv\config\applicationhost.config file and add two lines of <add>, one in the globalModules section and the other in the modules section, as the following:
        ...
            <add name="mod_HelloWorld" image="C:\privates\mod_HelloWorld.dll" />
        </globalModules>

        ... 

            <add name="mod_HelloWorld" />
        </modules>
9. Launch IE and send http://localhost request and now you will see the response body is replaced with "Hello world!!! 안녕하세요". (FYI, if the result is displayed with broken characters, the current encoding is not UTF8, which can be fixed by right-mouse-clicking the IE's main page, selecting "Encoding" context menu and choosing the "Unicode (UTF-8)" encoding.

Conclusion:

Now, I hope you feel confident about how to use the WriteEntityChunkByReference API for manipulating the response body and how to handle non English string to make response body with using this simple module.

If you are not clear yet, please try to read the code carefully and try to update the code as you want. I realize the best way to learn programing is to do it by myself without other's help. IIS native API, however, is too huge to catch them easily but you will feel it is actually not that huge eventually. 

I will try to introduce more interesting topic in the next time. 

 

 

 

 


Examples of IIS Powershell cmdlets

$
0
0

Summary:

This document explains how to specify the values of parameter values and how the configuration file is updated by IIS Powershell generic cmdlets such as Get-WebConfiguration and Get-WebConfigurationProperty so that users can use them effectively.

I'd like to inform that the configuration editor of IIS8 has an useful feature to generate IIS Powershell cmdlets. You can use that feature if you want to get the example usage quickly. 

  

  1. Examples how to use parameter values

-PSPATH

COMMAND Examples:  -PSPATH is used to specify the target web object such as server/site/web application/virtual directory and physical directory. The following examples show that there are two equivalent type of PSPATH

 

## Using the path form which is used by MWA and you can specify MACHINE or MACHINE/WEBROOT level as well in this form; The "MACHINE/WEBROOT/APPHOST" is equivalent to "IIS:\", which is another form of PSPATH

$filter = "appSettings"

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

Get-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName

 

## IIS Powershell provider style PSPATh, which starts with "IIS:\"

$pspath = 'IIS:\Sites\Default Web Site\webapplication1'

Get-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName

 

## Even -pspath parameter don't need to be specified if the current directory location is changed to that place

Cd  'IIS:\Sites\Default Web Site\webapplication1'

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

TIP

  1. For server level configurations such as config section which starts with system.applicationhost, we can skip to specify the pspath parameter also

-Filter

COMMAND Examples:  -Filter can be xpath form to specify a specific or multiple  items of IIS config object such as element/collection/attribute; It will be very useful for you to know various xpath style value to enumerate IIS configurations. 

 

## Specify a site element section with xpath style value

$filter = "//sites/site"

$propertyName = "id"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a site element section with full path value

$filter = "system.applicationHost/sites/site"

$propertyName = "id"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Enumerating site (NOTE: the following five xpath examples are equivalent  in IIS config file and shows that you can use wild card value. FYI, "." means a collection item, which can be optional for specifying collection items)

Get-WebConfiguration -filter /system.applicationHost/sites/site

Get-WebConfiguration -filter /system.applicationHost/sites/site/.

Get-WebConfiguration -filter /*/*/site

Get-WebConfiguration -filter //sites/site

Get-WebConfiguration -filter //*/sites/site

 

## Enumerating name attribute of site (NOTE: the following two xpath examples are equivalent)

Get-WebConfiguration -filter /system.applicationHost/sites/site/@name

Get-WebConfiguration -filter //sites/site/@name

Get-WebConfiguration -filter //sites/site/./@name

 

## Specify a certain site node with filtering with multiple attribute values

$filter = "/system.applicationHost/sites/site[@name='Default Web Site' and @id='1']"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain site node with a single attribute value

$filter = "/system.applicationHost/sites/site[@name='Default Web Site']"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain site node with contains() function to say that its attribute "name" should contain a specific string

$filter = "/system.applicationHost/sites/site[contains(@name,'Default')]" 

Get-WebConfigurationProperty -filter $filter -name $propertyName
 

## Specify a certain site node with last() function to say that its attribute "name"  should end with a specific string

$filter = "/system.applicationHost/sites/site[last(@name,'Site')]"

Get-WebConfigurationProperty -filter $filter -name $propertyName
 

## Specify a certain site node with starts-with() function to say that its attribute "name" should start with a specific string

$filter = "/system.applicationHost/sites/site[starts-with(@name,'Default')]"

Get-WebConfigurationProperty -filter $filter -name $propertyName
 

## Specify a certain site node with position() function to say it should be placed at first

$filter = "/system.applicationHost/sites/site[position()=1]"

Get-WebConfigurationProperty -filter $filter -name $propertyName
 

## Specify a certain site node with count() to say that its parent should have only one site node 

$filter = "//*[count(site)=1]/site"

Get-WebConfigurationProperty -filter $filter -name $propertyName
 

## Specify a certain site node with name() to say that the element name should be "site"

$filter = "//*[name()='site']"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain site node with local-name() to say that the element name should be "site"

$filter = "//*[local-name()='site']"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain site node with starts-with() function to say that the element name should start "site"  should end with a specific string

$filter = "//*[starts-with(name(),'site')]"

Get-WebConfigurationProperty -filter $filter -name $propertyName
 

## Specify a certain site node with concat() function to say that the combined string of name and id attributes should be a specific string, "Default Web Site1", which is "Default Web Site" + "1"

$filter = "/system.applicationHost/sites/site[concat(@name, @id)='Default Web Site1']"

Get-WebConfigurationProperty -filter $filter -name $propertyName
 

## Specify a certain node with substring-after() function to say that the node name should contains  a specific string such as "site"

$filter = "//*[substring-after(name(), 'site')]"

Get-WebConfigurationProperty -filter $filter -name $propertyName
 

## Specify a certain node with substring-before() function to say that the node name should contains  a specific string such as "ite"

$filter = "//*[substring-before(name(), 'ite')]"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain node with substring function to say that the node name's substring start 0th with length 2 should be a specific string such as "si"

$filter = "//*[substring(name(),0,2)='si']"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain node with string-length() function to say that the legnth of the node name should be 4

$filter = "//*[string-length(name())=4]"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain node with string-length() function to say that the legnth of the node name should be 4

$filter = "//*[string-length(name())=4]"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain site node with translate() function to say that its name attribute value should be "default web site" if "D" in the original string is replaced with "d", "W" with "w", and "S" with "s" as well

$filter ="/system.applicationHost/sites/site[translate(@name, 'DWS', 'dws')='default web site']"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain site node with compare-string-ordinal() function to say that its name attribute should be "default web site" in comparing case-in-sensitively

$filter ="/system.applicationHost/sites/site[compare-string-ordinal(@name,'default web site',true())=0]"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain site node with compare-string-ordinal() function to say that its name attribute should be "Default Web Site" in comparing case-in-sensitively

$filter ="/system.applicationHost/sites/site[compare-string-ordinal(@name,'Default Web Site',false())=0]"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain site node with compare-string-ordinal() function to say that its name attribute should be "Default Web Site" in comparing case-in-sensitively

$filter ="/system.applicationHost/sites/site[compare-string(@name,'Default Web Site',true())=0]"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Using "and" and "or" for set multiple condition using contains() function

$filter='/system.webServer/handlers[(contains(@accessPolicy, "Script") and contains(@accessPolicy, "Write")) or (contains(@accessPolicy, "Execute") and contains(@accessPolicy, "Write"))]'

Get-WebConfiguration -filter $filter -recurse

 

## following xpath functions are also supported:

Normalize-space(), Boolean(), Not(), Number(), Sum(), Floor(), Ceiling(), Round() and Compare-string()

-Name

COMMAND Examples:  -Name parameter is used by Get-WebConfigurationProperty and it is used to specify not only property name but also collection item

 

## Return attribute object for a specific attribute of "name"

Get-WebConfigurationProperty -filter "/system.applicationHost/sites/site" -name name

 

## Return list of collection objects  using "." or Collection which are special attribute name to specify collection items

Get-WebConfigurationProperty -filter "/system.applicationHost/sites" -name .

Get-WebConfigurationProperty -filter "/system.applicationHost/sites" -name Collection


NOTE: Even though the actual objects returned by the above two commands are exactly the same but the output in display could look different each other.

 

## When collection is used, users can filter out with query in the form of [attributeName=value] 

Get-WebConfigurationProperty -filter "/system.applicationHost/sites" -name Collection[name="Default Web Site"]

 

TIP

  1. The above command can be replaced with using xpath filtering from -filter value as the following:

Get-WebConfigurationProperty -filter "/system.applicationHost/sites/site[@name='DefaultWeb Site']" -name .

  1. Even users can use wild character in the filtering out form, which is not allowed in xpath

Get-WebConfigurationProperty -filter "/system.applicationHost/sites" -name Collection[name="Default*"]

  1. There are special purpose of property name such as Sections and SectionGroups to manage sections

 -Recurse

COMMAND Examples: When -Recurse parameter is used with Get-WebConfiguration or Get-WebConfigurationProperty, users can query recursively not only from the current directory

get-webconfiguration '/system.webServer/handlers[(contains(@accessPolicy, "Script") and contains(@accessPolicy, "Write")) or (contains(@accessPolicy, "Execute") and contains(@accessPolicy, "Write"))]' -recurse

TIP:

  1. You might be confused if you use the -recurse parameter from child level and you got no result. For the example, if you enable  basicAuthentication on Default Web Site and run the following command, you will get empty result. This is because the authentication setting is actually configured in the server level configuration file such as applicationhost.config using location tag of "<location path="Default Web Site">".
     

Get-WebConfigurationProperty '//basicAuthentication' -name enabled   -pspath "MACHINE/WEBROOT/APPHOST/Default

Web Site"  -Recurse

 

In the same situation, if you use the following command with specifying the server level for the pspath parameter, you will get the result.

Get-WebConfigurationProperty '//basicAuthentication' -name enabled   -pspath "MACHINE/WEBROOT/APPHOST"  -Recurse

 

If the authentication setting was configured in the web.config of Default Web Site's root directory after delegating the authentication configuration to site level, both of the above two commands  will work because the actual configuration is now set in the Default Web Site level.

-Value

COMMAND Examples:  When -Value  parameter is used by IIS powershell cmdlet, it usually set with a single string value (NOTE: if the value contains space, it should be quoted with " or ')
 

## The value can be hash table object if it is used to set a collection item

add-webconfiguration '/system.applicationHost/sites/site[@name="Default Web Site"]/bindings'-value @{protocol="http";bindingInformation="*:80:"} -pspath iis:\ 

 

  1. Adding  "file" attribute

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings file="test">    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

$propertyName = "file"

$propertyValue =  "test"

 

Set-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value $propertyValue

 

  1. Removing "file" attribute

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettingsfile="test">    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings/@file"

 

clear-WebConfiguration -pspath $pspath -filter appSettings/@file

 

  1. Locking "file" attribute only

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings lockAttributes="file">    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings/@file"

$lockType = "inclusive"

 

Add-WebConfigurationLock -pspath $pspath -filter $filter -type $lockType

 

  1. Unlock "file" attribute with removing the lockAttributes attribute, which is a specialized attribute

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings lockAttributes="file">    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings/@file"

 

Remove-WebConfigurationLock -pspath $pspath -filter $filter

 

  1. Locking all attributes except "file" attribute with using lockAllAttributesExcept attribute which is a specialized attribute

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings lockAllAttributesExcept="file">    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings/@file"

$lockType = "exclusive"

 

Add-WebConfigurationLock -pspath $pspath -filter $filter -type $lockType

 

  1. Removing  the exclusive lock which is set by lockAllAttributesExcept attribute which is a specialized attribute

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings lockAllAttributesExcept="file">    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

COMMAND Examples: (NOTE: Remove-WebConfigurationLock does not support removing the exclusive lock; As a work-around, we should remove the whole section and copy the previous items)

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

$propertyName = "."

 

$items = (get-webconfigurationproperty -pspath $pspath -filter $filter -name $propertyName).collection

 

Clear-WebConfiguration  -pspath $pspath -filter $filter

 

$items | foreach { Add-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value @{key=$_.key;value=$_.value}  }

 

  1. Adding collection item

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings file="test">    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

$propertyName = "."

$propertyValue =  @{key='ee';value='ee'}

 

Add-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value $propertyValue

 

  1. Modifying property value of collection item

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings file="test">    

      <add key="foo2" value="bar" />

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings/add[@key='foo']"

$propertyName = "key"

$propertyValue =  "foo2"

 

Set-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value $propertyValue

 

  1. Reverting to parent with removing whole config section

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

      <clear/>       

        <add key="foo" value="bar"/>

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

</configuration>

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

 

Clear-WebConfiguration  -pspath $pspath -filter $filter

 

  1. Removing <clear />

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

      <clear/>       

        <add key="foo" value="bar"/>

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

        <add key="foo" value="bar"/>

    </appSettings>

</configuration>

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

$propertyName = "."

 

$items = (get-webconfigurationproperty -pspath $pspath -filter $filter -name $propertyName).collection

 

Clear-WebConfiguration  -pspath $pspath -filter $filter

 

$items | foreach { Add-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value @{key=$_.key;value=$_.value}  }

 

  1. Removing all collection items of the current level only

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <remove key="foo_parent" />

      <add key="foo" value="bar"/>

      <add key="foo2" value="bar2"/>

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

      <remove key="foo_parent" />

    </appSettings>

</configuration>

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

$propertyName = "."

 

$items = (get-webconfigurationproperty -pspath $pspath -filter $filter -name $propertyName).collection  | where {$_.getmetadata("collectionItemFileConfigPath") -eq $pspath }

 

$items | foreach { Remove-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -AtElement @{key=$_.key}  }

 

  1. Remove a specific <remove> item of key value "foo_parent"

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

      <remove key="foo_parent" />

      <remove key="foo_parent2" />

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

      <remove key="foo_parent2" />

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$pspath_parent = 'MACHINE/WEBROOT/APPHOST/Default Web Site'

$filter = "appSettings"

$propertyName = "."

$KeyValue= "foo_parent"

 

$parentItems = (get-webconfigurationproperty -pspath $pspath_parent -filter $filter -name $propertyName).collection

$inheritedItems = (get-webconfigurationproperty -pspath $pspath -filter $filter -name $propertyName).collection  | where {$_.getmetadata("collectionItemFileConfigPath") -ne $pspath }

$localitems = (get-webconfigurationproperty -pspath $pspath -filter $filter -name $propertyName).collection  | where {$_.getmetadata("collectionItemFileConfigPath") -eq $pspath }

 

$removedItems = @{}

$parentItems | foreach {

     $item = $_

     $itemFound = $inheritedItems | where { ($_.key -eq $item.key) -and  ($_.value -eq $item.value) }

     if (($itemFound -eq $null) -and ( $item.key -ne $KeyValue))

     {

       $removedItems.add($item.key, $item.value)

     }

}

 

Clear-WebConfiguration  -pspath $pspath -filter $filter

 

$localitems | foreach { Add-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value @{key=$_.key;value=$_.value}  }

 

$removedItems.Keys | foreach { Remove-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -AtElement @{key=$_}  }

 

  1. Remove all collection items including items inherited from parents

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

     <add key="foo" value="bar"/>

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

    <clear/>        

    </appSettings>

</configuration>

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

$propertyName = "."


Rem
ove-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName

 

  1. Remove "foo_parent" collection item which is inherited from parent level)

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

     <add key="foo" value="bar"/>

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

       <remove key="foo_parent" />

        <add key="foo" value="bar"/>

    </appSettings>

</configuration>

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

$propertyName = "."

$propertyValue =  "foo_parent"

 

Remove-WebConfigurationProperty  -pspath $pspath -filter $filter -name $propertyName -AtElement @{key=$propertyValue}

 

  1. Remove "foo" collection item for a specific file such as default.aspx which is placed at the current directory

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar"/>

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

    <location path="default.aspx">

        <appSettings>

            <remove key="foo" />

        </appSettings>

    </location>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

$propertyName = "."

$propertyValue =  "foo"

$locationPath =  "default.aspx"

 

Remove-WebConfigurationProperty  -pspath $pspath -filter $filter -name $propertyName -AtElement @{key=$propertyValue} -location $locationPath

 

  1. Reverting to parent for the default.aspx location

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

    <location path="default.aspx">

        <appSettings>

            <remove key="foo" />

        </appSettings>

    </location>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

    <location path="default.aspx">

    </location>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

$propertyName = "."

$propertyValue =  "foo"

$locationPath =  "default.aspx"

 

clear-webconfiguration  -pspath $pspath -filter $filter -name $propertyName -AtElement @{key=$propertyValue} -location $locationPath

 

  1. Locking collection item

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings file="test">    

      <add key="foo" value="bar"lockItem="true"/>

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings/add[@key='foo']"

$lockType = "general"

 

Add-WebConfigurationLock -pspath $pspath -filter "appSettings/add[@key='foo']" -type $lockType

 

  1. Unlocking collection item

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar"lockItem="true"/>

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings file="test">    

      <add key="foo" value="bar"/>

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings/add[@key='foo']"

 

Remove-WebConfigurationLock -pspath $pspath  -filter $filter

 

  1. Set machine level with specifying framework version of v2.0, which is different to the default value -> This is only applicable for Windows 2012

FROM: for the root web.config file of .Net v2.0

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT'

$filter = "appSettings"

$propertyName = "file"

$propertyValue =  "test"

$clrVersion = "v2.0"

 

Set-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value $propertyValue -clr $clrVersion

 

  1. Locking item from section level

FROM: for the applicationhost.config file

...

</configuration>

 

TO:

...

    <appSettings lockItem="true" />

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST'

$filter = "appSettings"

$type="general"

 

Add-WebConfigurationLock-pspath $pspath -filter $filter

 

  1. Remove section level lock

FROM: for the applicationhost.config file

...

    <appSettings lockItem="true" />

</configuration>

 

TO:

    <appSettings/>

</configuration>

...

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST'

$filter = "appSettings"

 

Remove-WebConfigurationLock-pspath $pspath -filter $filter

 

  1. Add a new section group

FROM: for the applicationhost.config file

...

    </configSections>

...

 

TO:

        <sectionGroup name="MySectionGroup" />

    </configSections>

...

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST'

$filter = "/"

$propertyName = "sectionGroups"

$propertyValue =  "MySectionGroup"

 

Add-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value $propertyValue

 

  1. Delete a section group

FROM: for the applicationhost.config file

...

        <section name="MySection" />

    </configSections>

...

 

TO:

    </configSections>

...

 

COMMAND Examples:

 

## FYI, This is to show how to get the section object at root level

get-WebConfigurationProperty -pspath iis:\ -filter / -name sectionGroups["MySectionGroup"]

 

## Delete the section group

Remove-WebConfigurationProperty -pspath iis:\ -filter "/" -name sectionGroups["MySectionGroup"]

 

  1. Add a new section

FROM: for the applicationhost.config file

...

    </configSections>

...

 

TO:

        <section name="MySection" />

    </configSections>

...

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST'

$filter = "/"

$propertyName = "sections"

$propertyValue =  "MySection"

 

Add-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value $propertyValue

 

  1. Delete a section

FROM: for the applicationhost.config file

...

        <section name="MySection" />

    </configSections>

...

 

TO:

    </configSections>

...

 

COMMAND Examples:

 

## FYI, This is to show how to get the section object at root level

get-WebConfigurationProperty -pspath iis:\ -filter / -name sections["MySection"]

 

## Delete the section

Remove-WebConfigurationProperty -pspath iis:\ -filter "/" -name sections["MySection"]

 

  1. Add a new section under a specific section group

FROM: for the applicationhost.config file

...

        <sectionGroup name="MySectionGroup" />

    </configSections>

...

 

TO:

        <sectionGroup name="MySectionGroup">

             <section name="MyChildSection" />

        </sectionGroup>           

    </configSections>

...

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST'

$filter = "/MySectionGroup"

$propertyName = "sections"

$propertyValue =  "MyChildSection"

 

Add-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value $propertyValue

 

  1. Delete a section under a specific section group

FROM: for the applicationhost.config file

...

        <sectionGroup name="MySectionGroup">

             <section name="MyChildSection" />

        </sectionGroup>           

    </configSections>

...

 

TO:

        <sectionGroup name="MySectionGroup" />

    </configSections>

...

 

COMMAND Examples:

 

## FYI, This is to show how to get the section object under the specific section group

get-WebConfigurationProperty -pspath iis:\ -filter /MySectionGroup -name sections["MyChildSection"]

 

## Delete the section

Remove-WebConfigurationProperty -pspath iis:\ -filter "/MySectionGroup" -name sections["MyChildSection"]

 

  1. Configure "Deny" for OverrideModeDefault attribute of a specific section

FROM: for the applicationhost.config file

...

        <sectionGroup name="system.webServer">

            <section name="asp" overrideModeDefault="Deny" />

...

 

TO:

        <sectionGroup name="system.webServer">

            <section name="asp" overrideModeDefault="Allow" />

...

 

COMMAND Examples:

 

Set-WebConfigurationProperty -filter /system.webServer -name 'sections["asp"].OverrideModeDefault' -value Allow -pspath iis:\

 

 

IIS Powershell User guide - Comparing representative IIS UI tasks

$
0
0
  1. [File System] Open Explorer window for Default Web Site's home directory
    $path=$(get-item 'iis:sitesdefault web site').physicalPath
    $path=[system.environment]::ExpandEnvironmentVariables($path)
    explorer $path

    Related UI Task:"Explorer"

  2. [File System] Open Explorer window for Default Web Site's home directory using "DirectoryName" property
    $path=$(get-item 'iis:sitesdefault web siteiisstart.htm').directoryName
    explorer $path

    Related UI Task:"Explorer"

  3. [File System] Create File and set file content programmatically
    $file=new-item demo.htm -type file
    set-content $file.FullName "Hey, dude!"

    Related UI Task:"Explorer"

  4. [File System] Set "Deny" for administrator user account for 'iisstart.htm' file and grant access permission for NTAccount
    $file=$(get-item "iis:sitesDefault Web Siteiisstart.htm ")
    $dacl=$file.GetAccessControl()
    $newRule=New-Object Security.AccessControl.FileSystemAccessRule Administrator, Modify, Deny
    $modified=$false
    $dacl.ModifyAccessRule("Add", $newRule, [ref]$modified)
    $file.SetAccessControl($dacl)
    $file.GetAccessControl().GetAccessRules($true, $true, [System.Security.Principal.NTAccount])

    Related UI Task:"Edit Permissions..."

  5. [Application Pool] Get the list of application pools
    dir iis:apppools

    Related UI Task:"Application Pools" treeview

  6. [Application Pool] Create a new pool
    New-Item iis:apppoolsdemoAppPool

    Or, you can use other task-based cmdlet(s) instead:

    New-AppPool demoAppPool

    NOTE: New-AppPool cannot use full path name such as “iis:appPoolsdemoAppPool” like other user-friendly-named cmdlets

    Related UI Task:"Add Application Pool..."

  7. [Application Pool] Rename an Application Pool
    Rename-Item iis:apppoolsdefaultapppool newAppPoolName

    Related UI Task:"Rename "

  8. [Application Pool] Remove an Application Pool
    Remove-Item iis:apppoolsdefaultapppool

    Or, you can use other task-based  cmdlet(s) instead:

    Remove-AppPool defaultapppool

    Related UI Task:"Remove "

  9. [Application Pool] Stop/Start/Recycle Application Pool
    Start-WebItem IIS:AppPoolsDefaultAppPoolStop-WebItem IIS:AppPoolsDefaultAppPoolRestart-WebItem IIS:AppPoolsDefaultAppPool

    Or, you can use other task-based cmdlet(s) instead:

    Start-AppPool DefaultAppPool
    Stop-AppPool DefaultAppPool
    Restart-AppPool DefaultAppPool

    Related UI Task:"Stop/Start/Recycle"

  10. [Application Pool] Get the current status of Application Pool
    Get-WebItemState iis:apppoolsdefaultapppool

    Or, you can use other task-based  cmdlet(s) instead:

    Get-AppPoolState defaultapppool

    Related UI Task:"Stop/Start/Recycle"

  11. [Application Pool] Get the list of application which is belonged to an Application Pool
    function ConvertFrom-ItemXPath($itemXpath)
    {
        $result = new-object psobject
    
        $tempString = $itemXPath.substring($itemXPath.IndexOf("@name"))
        add-member -in $result noteproperty Site $tempString.Split("'")[1]
    
        $tempString = $itemXPath.substring($itemXPath.IndexOf("@path"))
        add-member -in $result noteproperty Application $tempString.Split("'")[1]
        return $result
    }
    
    $applications = get-webconfiguration //application[@applicationPool]
    $applications | select itemXpath, applicationpool | foreach {if ($_.applicationPool -eq "DefaultAppPool") {ConvertFrom-ItemXPath ($_.itemXpath)}}
    

    Related UI Task:"View Applications"

  12. [Application Pool] Get Application Pool Default Settings
    $subsections=get-webconfiguration //applicationPoolDefaults//. -PSPATH iis:
    $subsections | foreach { $_.attributes | select name,value }
    PS IIS:\> $subsections = get-webconfiguration //applicationPoolDefaults//.
    PS IIS:\> $subsections | foreach { $_.attributes | select name,value }
    Name                                    Value
    ----                                    -----
    namequeueLength                         1000
    autoStart                               True
    enable32BitAppOnWin64                   False
    managedRuntimeVersion                   v2.0
    enableConfigurationOverride             True
    managedPipelineMode                     0
    passAnonymousToken                      True
    identityType                            2
    userName
    password
    loadUserProfile                         False
    manualGroupMembership                   False
    idleTimeout                             00:20:00
    maxProcesses                            1
    shutdownTimeLimit                       00:01:30
    startupTimeLimit                        00:01:30
    pingingEnabled                          True
    pingInterval                            00:00:30
    pingResponseTime                        00:01:30
    disallowOverlappingRotation             False
    disallowRotationOnConfigChange          False
    logEventOnRecycle                       137
    memory                                  0
    privateMemory                           0
    requests                                0
    time                                    1.05:00:00
    value                                   11:59:00
    value                                   11:32:00
    loadBalancerCapabilities                1
    orphanWorkerProcess                     False
    orphanActionExe
    orphanActionParams
    rapidFailProtection                     False
    rapidFailProtectionInterval             00:05:00
    rapidFailProtectionMaxCrashes           5
    autoShutdownExe
    autoShutdownParamslimit                 0
    action                                  0
    resetInterval                           00:05:00
    smpAffinitized                          False
    smpProcessorAffinityMask                4294967295

    logEventOnRecyle property value shows number value, which is not human-readable. You can get the text enum value by querying the specific property instead such as shown in the following:

    get-webconfiguration //applicationPoolDefaults/recycling/@logEventOnRecycle
    PS IIS:\> get-webconfiguration //applicationPoolDefaults/recycling/@logEventOnRecycleTime,Memory

    Related UI Task:"Set Application Pool Defaults..."

  13. [Application Pool] Set Application Pool Default Settings

    Case1: Setting queueLength, which is “property” type

    set-webconfigurationproperty /system.applicationHost/applicationPools/applicationPoolDefaults[1]/failure[1] -name rapidFailProtectionMaxCrashes -value 10
    # You could get the section path of the target property programmatically
    PS IIS:\> get-webconfiguration //*[@rapidFailProtectionMaxCrashes] | foreach {$_.itemXPath}/system.applicationHost/applicationPools/applicationPoolDefaults[1]/failure[1]/system.applicationHost/applicationPools/add[@name='DefaultAppPool']/failure[1]/system.applicationHost/applicationPools/add[@name='Classic .NET AppPool']/failure[1]
    # Set the property value with the section path
    PS IIS:\> set-webconfigurationproperty /system.applicationHost/applicationPools/applicationPoolDefaults[1]/failure[1] -name rapidFailProtectionMaxCrashes -value 10
    NOTE: “applicationPoolDefaults[1]/failure[1]” is equivalent to “applicationPoolDefaults/failure”.

    Case2: Setting schedule, which is “element” type (shown as “Specific Times” in UI)

    add-webconfiguration /system.applicationHost/applicationPools/applicationPoolDefaults/recycling/periodicRestart/schedule -value (New-TimeSpan -h 9 -m30)
    # Add new ‘Add’ element with a new-timespan value and add-webconfiguration cmdlet
    PS IIS:\> add-webconfiguration /system.applicationHost/applicationPools/applicationPoolDefaults/recycling/periodicRestart/schedule -value (New-TimeSpan -h 9 -m30) # Confirm the new value is added
    PS IIS:\> get-webconfiguration /system.applicationHost/applicationPools/applicationPoolDefaults/recycling/periodicRestart/schedule/add | select value value-----09:30:00

    Related UI Task:"Set Application Pool Defaults..."

  14. [Application Pool] Get configuration settings for a specific application pool
    $configSection="/system.applicationHost/applicationPools/add[@name='DefaultAppPool']//."
    $subsections=get-webconfiguration $configSection -PSPath iis:
    $subsections | foreach { $_.attributes | select name,value }

    Or, you can use “*” instead of the full config section path:

    $subsections=get-webconfiguration '//*[@name="DefaultAppPool"]//.' -PSPath iis:
    $subsections | foreach { $_.attributes | select name,value }

    Related UI Task:"Advanced Settings..."

  15. [Application Pool] Set configuration settings for a specific application pool

    Case1: Setting logEventOnRecycle, which is "enum property" type

    $configSection="/system.applicationHost/applicationPools/add[@name='DefaultAppPool']/recycling"
    set-webconfigurationproperty $configSection -name logEventOnRecycle -value 1 -PSPath iis:\

    NOTE: The value could be set with "Time" in the next version instead of 1 for the above example

    Related UI Task:"Advanced Settings..."

  16. [Application Pool] Get the list of application pools
    Dir iis:sites

    Related UI Task:"Sites" treeview

  17. [Sites] Create a new Web Site

    Case1: Create web site with single binding

    $binding=@{protocol="http";bindingInformation="*:80:hostname"}
    new-item "iis:sitesdemoSite" -type site –physicalPath c:demoSite -bindings $binding

    Case2: Create web site with multiple binding and specific id

    $binding=(@{protocol="http";bindingInformation="*:80:hostname"},@{protocol="http";bindingInformation="*:80:hostname2"})
    new-item "iis:sitesdemoSite" -type site -physicalPath c:demoSite -bindings $binding -id 555

    Or, you can use other task-based cmdlet(s) instead:

    New-WebSite -Name DemoSite -Port 80 -HostHeader hostname –PhysicalPath c:demoSite –ID 555
    New-WebBinding -Site DemoSite -Port 80 -IPAddress * -HostHeader hostname2

    Related UI Task:"Add Web Site..." wizard

  18. [Sites] Set bindings

    Case1: Create SSL Binding (127.0.0.1!443)

    $certObect=get-item cert:LocalMachineMyE48803C3A6DDC8F2BFE3D8B7B7D56BBA70270F92new-item IIS:SslBindings127.0.0.1!443 -value $certObect
    PS IIS:\> dir cert:\LocalMachine\My     Directory: Microsoft.PowerShell.Security\Certificate::LocalMachine\My
    Thumbprint                                Subject
    ----------                                -------
    E48803C3A6DDC8F2BFE3D8B7B7D56BBA70270F92  CN=WMSvc-JHKIM-WTT3
    
    PS IIS:\> $certObect = get-item cert:\LocalMachine\My\E48803C3A6DDC8F2BFE3D8B7B7D56BBA70270F92
    PS IIS:\> new-item IIS:\SslBindings\127.0.0.1!443 -value $certObect
    IP Address       Port Store            Sites
    ----------       ---- -----            -----
    127.0.0.1        443  My

    Case2: Set 'Bindings' property with multiple binding information including the SSL binding which was created above.

    $newBinding=(@{protocol="http";bindingInformation="127.0.0.1:80:normalSite"},@{protocol="https";bindingInformation="127.0.0.1:443:securedSite"})
    Set-itemproperty "IIS:SitesDefault Web Site" -name bindings -value $newBinding

    Or, you can use other task-based  cmdlet(s) instead:

    New-WebBinding -Site "Default Web Site" -Port 443 -IPAddress 127.0.0.1 -HostHeader securedSite

    NOTE: you can also use set-webconfiguration, set-webconfiguration or add-webconfigurationProperty.

    Set-Webconfiguration '/system.applicationHost/sites/site[@name="Default Web Site"]/bindings' -value $newBinding  -PSPath iis:
    Set-WebconfigurationProperty '/system.applicationHost/sites/site[@name="Default Web Site"]' -name bindings.collection -value $newBinding -at 0  -PSPath iis:
    Add-WebconfigurationProperty '/system.applicationHost/sites/site[@name="Default Web Site"]' -name bindings.collection -value @{protocol="https";bindingInformation="127.0.0.1:443:securedSite"} -at 0  -PSPath iis:

    Case3: Change a certain value of existing 'Bindings' property using other task-based  cmdlet.

    Set-WebBinding -Site "Default Web Site" -Port 443 -IPAddress 127.0.0.1 -HostHeader securedSite -name Port -value 444

    Case4: Removing binding information using other task-based  cmdlet.

    Remove-WebBinding -Site "Default Web Site" -Port 443 -IPAddress 127.0.0.1 -HostHeader securedSite

    Or, you can use Remove-WebConfigurationProperty

    Remove-WebconfigurationProperty '/system.applicationHost/sites/site[@name="Default Web Site"]' -name Bindings.collection -at @{protocol="https";bindingInformation="127.0.0.1:443:securedSite"}  -PSPath iis:

    Case5: Clear all the binding information of a certain web site

    Clear-Webconfiguration '/system.applicationHost/sites/site[@name="Default Web Site"]/bindings' -PSPath iis:

    NOTE: you can also use clear-itemproperty instead:

    Clear-ItemProperty 'iis:sitesDefault Web Site' -name bindings

    Related UI Task:"Bindings..."

  19. [Sites] Rename an Web Site
    Rename-Item "iis:sitesdefault web site" newWebSiteName

    Related UI Task:"Rename"

  20. [Sites] Remove an Web Site
    Remove-Item "iis:sitesdefault web site"

    Or, you can use other task-based  cmdlet(s) instead:

    Remove-WebSite " default web site"

    Related UI Task:"Remove "

  21. [Sites] Stop/Start/Restart Web Site
    Start-WebItem "IIS:SitesDefault Web Site"
    Stop-WebItem "IIS:SitesDefault Web Site"
    Restart-WebItem "IIS:SitesDefault Web Site"

    Or, you can use other task-based  cmdlet(s) instead:

    Start-WebSite "Default Web Site"
    Stop-WebSite "Default Web Site"
    Restart-WebSite "Default Web Site"

    Related UI Task:"Stop/Start/Restart"

  22. [Sites] Get the current status of Web Site
    Get-WebItemState "IIS:SitesDefault Web Site"

    Or, you can use other task-based  cmdlet(s) instead:

    Get-WebSiteState "Default Web Site"

    Related UI Task:"Stop/Start/Recycle"

  23. [Sites] Get Web Site Defaults Settings
    $subsections=get-webconfiguration //siteDefaults//. -PSPATH iis:
    $subsections | foreach { $_.attributes | select name,value }
    PS IIS:\> $subsections = get-webconfiguration //siteDefaults//. -PSPATH iis:\
    PS IIS:\> $subsections | foreach { $_.attributes | select name,value }
    Name                                    Value
    ----                                    -----
    nameid                                      0
    serverAutoStart                         True
    maxBandwidth                            4294967295
    maxConnections                          4294967295
    connectionTimeout                       00:02:00
    logExtFileFlags                         2215887
    customLogPluginClsidlogFormat                               2
    directory                               %SystemDrive%\inetpub\logs\LogFiles
    period                                  1
    truncateSize                            20971520
    localTimeRollover                       False
    enabled                                 True
    enabled                                 False
    directory                               %SystemDrive%\inetpub\logs\FailedReq...
    maxLogFiles                             50
    maxLogFileSizeKB                        512
    customActionsEnabled                    False
    allowUTF8                               True
    serverAutoStart                         True
    unauthenticatedTimeout                  30
    controlChannelTimeout                   120
    dataChannelTimeout                      30
    disableSocketPooling                    False
    serverListenBacklog                     60
    minBytesPerSecond                       240
    maxConnections                          4294967295
    resetOnMaxConnections                   False
    maxBandwidth                            4294967295
    matchClientAddressForPort               True
    matchClientAddressForPasv               True
    maxCommandLine                          4096
    allowUnlisted                           True
    serverCertHashserverCertStoreName       MY
    ssl128                                  False
    controlChannelPolicy                    1
    dataChannelPolicy                       1
    clientCertificatePolicy                 0
    useActiveDirectoryMapping               False
    validationFlags                         0
    revocationFreshnessTime                 00:00:00
    revocationUrlRetrievalTimeout           00:01:00
    enabled                                 False
    userName                                IUSRpassword
    defaultLogonDomain                      NT AUTHORITY
    logonMethod                             3
    enabled                                 False
    defaultLogonDomain
    logonMethod                             3
    enabled                                 False
    impersonationLevel                      1
    exitMessage
    greetingMessage
    bannerMessage
    maxClientsMessage
    suppressDefaultBanner                   False
    allowLocalDetailedErrors                True
    expandVariables                         False
    keepPartialUploads                      False
    allowReplaceOnRename                    False
    allowReadUploadsInProgress              False
    externalIp4Addressmode                  4
    adUserName
    adPasswordadCacheRefresh                00:01:00
    showFlags                               0
    virtualDirectoryTimeout                 5
    logExtFileFlags                         14716367
    directory                               D:\inetpub\logs\LogFiles
    period                                  1
    truncateSize                            20971520
    localTimeRollover                       False
    enabled                                 True
    selectiveLogging                        7

    Related UI Task:"Set Web Site Defaults..."

  24. [Sites] Set Web Site Default Settings

    Case1: Setting connectionTimeout

    set-webconfigurationproperty "/system.applicationHost/sites/siteDefaults[1]/limits[1]" -name connectionTimeout -value (New-TimeSpan -sec 130)
    # You could get the section path of the target property programmatically
    PS IIS:\> get-webconfiguration //*[@connectionTimeout] | foreach {$_.itemxpath}/system.applicationHost/webLimits/system.applicationHost/sites/siteDefaults[1]/limits[1]/system.applicationHost/sites/site[@name='Default Web Site' and @id='1']/limits[1]
    # Set the property value with the section path
    PS IIS:\> set-webconfigurationproperty "/system.applicationHost/sites/siteDefaults[1]/limits[1]" -name connectionTimeout -value (New-TimeSpan -sec 130)

    Related UI Task:"Set Web Site Defaults..."

  25. [Sites] Get configuration settings for a specific web site
    $configSection="/system.applicationHost/sites/site[@name='Default Web Site']//."
    $subsections=get-webconfiguration $configSection -PSPath iis:
    $subsections | foreach { $_.attributes | select name,value }

    Or, you can use “*” instead of the full config section path:

    $subsections=get-webconfiguration '//*[@name="Default Web Site"]//.' -PSPath iis:
    $subsections | foreach { $_.attributes | select name,value }

    Related UI Task:"Advanced Settings..."

  26. [Sites] Set configuration settings for a specific web site

    Case1: Setting maxLogFiles

    $configSection="/system.applicationHost/sites/site[@name='Default Web Site' and @id='1']/traceFailedRequestsLogging"
    set-webconfigurationproperty $configSection -name maxLogFiles -value 60 -PSPath iis:

    If you are trying to change basic properties, you could also use set-itemProperty as shown in the following:

    Case2: 'Application Pool' property

    Set-Itemproperty IIS:SitesDemoSite -name applicationPool -value demo AppPool

    Case3: 'Physical Path' property

    set-itemproperty IIS:SitesDemoSite -name physicalPath -value c:demoSite2

    Case4: 'username' property

    set-itemproperty IIS:SitesDemoSite -name userName -value newUserId

    Case5: 'password' property

    set-itemproperty IIS:SitesDemoSite -name password -value newPassword

     Related UI Task:"Advanced Settings..." 

  27. [Sites] Set Failed Request Tracing for a specific web site

    Case1: Enable Freb for a specific web site with setting maxLogFiles and directory

    $configSection="/system.applicationHost/sites/site[@name='Default Web Site' and @id='1']/traceFailedRequestsLogging"
    set-webconfigurationproperty $configSection -name maxLogFiles -value 60 -PSPath iis:
    set-webconfigurationproperty $configSection -name directory -value c:MyFailedReqLogFiles -PSPath iis:

    Or, you can use other task-based  cmdlet(s) instead:

    Enable-Freb -Site "default web site" -Directory "c:MyFailedReqLogFiles" -MaxLogFileSize 555

    Case2: Disable Freb for a specific web site

    $configSection="/system.applicationHost/sites/site[@name='Default Web Site' and @id='1']/traceFailedRequestsLogging"
    set-webconfigurationproperty $configSection -name enabled -value false -PSPath iis:

    Or, you can use other task-based  cmdlet(s) instead:

    Disable-Freb -Site "default web site"

    Case3: Clear Freb data for a specific web site

    If you use Enable-Freb, it creates following default setting of Freb settings for the specified sites. We can clear them by this way.

    <?xml version="1.0" encoding="UTF-8"?><configuration>    <system.webServer>        <tracing>            <traceFailedRequests>                <add path="*">                    <traceAreas>                        <add provider="WWW Server" areas="Authentication,Security,Filter,StaticFile,CGI,Compression,Cache,RequestNotifications,Module" verbosity="Verbose" />                        <add provider="ASP" verbosity="Verbose" />                        <add provider="ISAPI Extension" verbosity="Verbose" />                        <add provider="ASPNET" areas="Infrastructure,Module,Page,AppServices" verbosity="Verbose" />                    </traceAreas>                    <failureDefinitions timeTaken="00:00:30" statusCodes="500" verbosity="Warning" />                </add>            </traceFailedRequests>        </tracing>    </system.webServer></configuration>
    Clear-WebConfiguration /system.webServer/tracing/traceFailedRequests -PSPath "iis:sitesdefault web site"

    Or, you can use other task-based  cmdlet(s) instead:

    Clear-FrebData -Site "default web site"

    Related UI Task:"Advanced Settings..."

  28. [Management] Read default feature Delegation settings

    Case1: Dump all sectionGroups

    get-webconfigurationproperty / -name sectiongroups

    Case2: Dump specific sectionGroup such as "system.applicationHost"

    get-webconfigurationproperty / -name sectiongroups["system.applicationHost"]

    Case3: Dump all sections under "/" group

    get-webconfigurationproperty / -name Sections

    NOTE: You will see empty value because IIS configuration system does not have section under "root" level by default

    Case4: Dump all sections under specific sectionGroup such as "system.webServer"

    $sections=get-webconfigurationproperty /system.webserver -name Sections
    $sections | select Name,OverrideModeDefault
    PS IIS:\> $sections = get-webconfigurationproperty /system.webserver -name Sections
    PS IIS:\> $sections | select Name,OverrideModeDefault
    Name                                                        OverrideModeDefault
    ----                                                        -------------------
    httpProtocol                                                Allow
    httpErrors                                                  Deny
    httpRedirect                                                Allow
    globalModules                                               Deny
    cgi                                                         Deny
    serverRuntime                                               Deny
    directoryBrowse                                             Allow
    urlCompression                                              Allow
    httpLogging                                                 Deny
    modules                                                     Deny
    odbcLogging                                                 Deny
    validation                                                  Allow
    fastCgi                                                     Deny
    handlers                                                    Deny
    httpTracing                                                 Deny
    staticContent                                               Allow
    isapiFilters                                                Deny
    defaultDocument                                             Allow
    asp                                                         Deny
    httpCompression                                             Deny
    serverSideInclude                                           Deny
    caching                                                     Allow

    NOTE: Now you can see the default override mode for "ASP" config section is deny, which means we can configure ASP related properties only for 'server' level

    Related UI Task:UI Feature: "Feature Delegation" page

  29. [Management] Add/Remove customized IIS config section

    Case1: Add "myGroup" sectiongroup under root

    add-webconfigurationproperty / -name SectionGroups -value myGroup

    Case2: Add "mySection" section under the myGroup sectiongroup which was created above

    add-webconfigurationproperty /myGroup -name Sections -value mySection

    Case3: Set OverrideModeDefault for the newly created section, "mySection"

    set-webconfigurationproperty /myGroup -name Sections["mySection"].OverrideModeDefault -value Deny

    Case4: Set AllowDefinition for the newly created section, "mySection"

    set-webconfigurationproperty /myGroup -name Sections["mySection"].AllowDefinition -value AppHostOnly

    Case5: Set AllowLocation for the newly created section, "mySection"

    set-webconfigurationproperty /myGroup -name Sections["mySection"].AllowLocation -value false

    Case6: Remove the "mySection" section which were created above

    remove-webconfigurationproperty /myGroup -name Sections -at mySection

    Case7: Remove the "myGroup" sectiongroup which were created above

    remove-webconfigurationproperty / -name SectionGroups -at myGroup

    Related UI Task:UI Feature: UI has no related task for this.

  30. [Management] Configure Feature Delegation related settings

    NOTE: Before changing delegation setting of a config section, you would need to remove previously configured properties and elements of the section and re-configure them again after the delegation setting is updated.

    This is an example of how to remove ASP sections using clear-webconfiguration cmdlet:

    clear-webconfiguration /system.webServer/asp -pspath MACHINE/WEBROOT/A
    PPHOST/testSite
    clear-webconfiguration /system.webServer/asp -pspath MACHINE/WEBROOT/A
    PPHOST
    # Get the list of previously configured items using -recurse option
    PS IIS:\> get-webconfiguration //asp -Recurse
    SectionPath                             PSPath
    -----------                             ------
    /system.webServer/asp                   MACHINE/WEBROOT/APPHOST/system.webServer/asp                   MACHINE/WEBROOT/APPHOST/testSite
    # Clear those items using clear-webconfiguration
    PS IIS:\> clear-webconfiguration /system.webServer/asp -pspath MACHINE/WEBROOT/APPHOST/testSitePS IIS:\> clear-webconfiguration /system.webServer/asp -pspath MACHINE/WEBROOT/APPHOST

    Case1: Read the current Delegation setting of ASP feature for 'server' level

    get-webconfiguration //asp iis: | select OverrideMode
    PS IIS:\> get-webconfiguration //asp iis:\ | select
    OverrideMode
    OverrideMode------------Inherit

    NOTE: The value "inherit" means it uses the default override mode and it is actually "Deny" in the default IIS configuration

    Case2: Set "Read-Write" for ASP feature for 'server' level

    set-webconfiguration //asp -metadata overrideMode -value Allow -PSPath iis:

    Case3: Set "Not Delegated" for ASP feature for 'server' level

    NOTE: "Not Delegated" task is only applicable to IIS UI world. Please use "Read Only" which is explained below.

    Case4: Set "Read Only" for ASP feature for 'server' level

    set-webconfiguration //asp -metadata overrideMode -value Deny -PSPath iis:

    Case5: Set "Reset to Inherited" for ASP feature for 'server' level

    set-webconfiguration //asp -metadata overrideMode -value Inherit -PSPath iis:

    Case6: Change Delegation settings for 'site' level

    set-webconfiguration //asp -metadata overrideMode -value Inherit -PSPath "iis:sitesdefault web site"

    Case7: Change Delegation settings for 'site' level using location

    set-webconfiguration //asp -metadata overrideMode -value Inherit -PSPath "iis:sites" -Location "default web site"

    Related UI Task:UI Feature: "Feature Delegation" page

  31. [IIS] Configure Clasic ASP properties

    Case1: Read all ASP settings from 'server' level

    $subsections=get-webconfiguration //asp//. -PSPATH iis:
    $subsections | foreach { $_.attributes | select name,value }

    Case2: Read all ASP settings from 'web site' level such as "Default Web Site"

    $subsections=get-webconfiguration //asp//. -PSPATH "iis:sitesdefault web site"
    $subsections | foreach { $_.attributes | select name,value }

    Case3: Read all ASP settings from 'web application' level such as "DemoApplication "

    $subsections=get-webconfiguration //asp//. -PSPATH "iis:sitesdefault web sitedemoapplication"
    $subsections | foreach { $_.attributes | select name,value }

    Case4: Read all ASP settings from 'file' level which is under an Web Site

    $subsections=get-webconfiguration //asp//. -PSPATH "iis:sitesdefault web site" -location iisstart.htm
    $subsections | foreach { $_.attributes | select name,value }

    Case5: Write an ASP setting, keepSessionIdSecure, for 'server' level

    set-webconfigurationproperty "/system.webServer/asp/session[1]" -name keepSessionIdSecure -value true -PSPath iis:
    # You could get the section path of the target property programmaticallyPS IIS:> get-webconfiguration //*[@keepSessionIdSecure] | foreach {$_.itemxpath}/system.webServer/asp/session[1]
    # Set the property value with the section path
    PS IIS:> set-webconfigurationproperty "/system.webServer/asp/session[1]" -name keepSessionIdSecure -value true -PSPath iis:

    Case6: Write an ASP setting, keepSessionIdSecure, for 'site' level

    set-webconfigurationproperty "/system.webServer/asp/session[1]" -name keepSessionIdSecure -value true -PSPath "iis:sitesdefault web site"

    Case5: Write an ASP setting, keepSessionIdSecure, for 'file' level which is under an Web Site

    set-webconfigurationproperty "/system.webServer/asp/session[1]" -name keepSessionIdSecure -value true -PSPath "iis:sitesdefault web site" -location iisstart.htm

     Related UI Task:UI Feature: "ASP" page 

  32. [IIS] Configure Authentication properties

    Case1: List all of authentications and from 'server' level

    get-webconfiguration /system.webServer/security/authentication/*[@enabled] -PSPath iis: | select ItemXPath,enabled

    Case2: List all of authentications and from 'site' level

    get-webconfiguration /system.webServer/security/authentication/*[@enabled] -PSPath "iis:sitesdefault web site"| select ItemXPath,enabled

    NOTE: You can also get from other levels adjusting the value -PSPath and -Location parameter values

    Case3: Get all of Anonymous authentication properties from 'server' level

    $attributes=(Get-WebConfiguration /system.webServer/security/authentication/anonymousAuthentication -PSPath iis:).attributes
    $attributes | select name,value

    NOTE: You can also get from other levels adjusting the value -PSPath and -Location parameter values

    Case4: Change userName property for Anonymous authentication properties from 'server' level

    Set-WebConfigurationproperty system.webServer/security/authentication/anonymousAuthentication -name userName -value "" -PSPath iis:

    NOTE: You can also set for other levels adjusting the value -PSPath and -Location parameter values

    Related UI Task:UI Feature: "Authentication" page

  33. [IIS] Configure Module elements and properties which are configured in globalModules section

    Case1: List all native modules

    (Get-WebConfiguration //globalmodules).collection -PSPath iis:

    Case2: Add a new native modue at the bottom index of the existing modules

    Add-WebConfigurationProperty //globalmodules -name collection -value @{name='testmodule';image='c:test.dll'} -PSPath iis:

    Or, you can use other task-based  cmdlet(s) instead:

    New-WebModule -Name testmodule -Image c:test.dll -Precondition "integratedMode"

    Case3: Add a new native modue at the top index of the existing modules

    Add-WebConfigurationProperty //globalmodules -name collection -value @{name='testmodule';image='c:test.dll'} -at 0 -PSPath iis:

    Case4: Remove a native modue with a number index value

    Remove-WebConfigurationProperty //globalmodules -name collection -at 0 -PSPath iis:

    Case5: Remove a native modue with a hashtable index value

    Remove-WebConfigurationProperty //globalmodules -name collection -at @{name='testmodule';image='c:test.dll'} -PSPath iis:

    Or, you can use other task-based  cmdlet(s) instead:

    Remove-WebModule -Name testmodule

    Case6: Get the attributes for a specific module

    $modules=(get-webconfiguration //globalmodules -PSPath iis:).collection
    $modules | foreach {if ($_.name -eq "cgiModule") { $_.attributes | select name, value}}

    Case7: Change an attribute value for a specific module

    Get-Webconfigurationproperty '//globalmodules/add[@name="CgiModule"]' -name image -PSPath iis:
    Set-Webconfigurationproperty '//globalmodules/add[@name="CgiModule"]' -name image -value %windir%System32inetsrvcgi.dll -PSPath iis:

    Related UI Task:UI Feature: "Modules" page

  34. [IIS] Configure Module elements and properties

    Case1: Enable/Disable a native modue

    Add-WebConfigurationProperty //modules -name collection -value @{name='testmodule';lockItem='true'}  -at 0 -PSPath iis:

    Or, you can use other task-based  cmdlet(s) instead:

    Enable-WebModule -Name testModule

    Case2: Add a new managedModule

    Add-WebConfigurationProperty //modules -name collection -value @{name='newManagedModule';type='Microsoft.IIS.DemoModule'}  -PSPath iis:

    Or, you can use other task-based  cmdlet(s) instead:

    New-Managedwebmodule -name newManagedModule -Type Microsoft.IIS.DemoModule

    Case3: Disable module by removing the module element from the <modules> section

    Remove-WebConfigurationProperty //modules -name collection -at @{name='testmodule';lockItem='true'}  -PSPath iis:

    Or, you can use other task-based  cmdlet(s) instead:

    Disable-WebModule -Name testModule

    Case4: List all of enabled modules from 'server' level

    (get-webconfiguration //modules -PSPath iis:).collection -PSPath iis:

    Or, you can use other task-based  cmdlet(s) instead:

    Get-WebModule -PSPath iis: -enabled

    Case5: Get the attributes for a specific module

    $modules=(get-webconfiguration //modules -PSPath iis:).collection
    $modules | foreach {if ($_.name -eq "cgiModule") { $_.attributes | select name, value}}

    Case6: Change an attribute value for a specific module

    Get-Webconfigurationproperty '//modules/add[@name="CgiModule"]' -name lockItem -PSPath iis:
    Set-Webconfigurationproperty '//modules/add[@name="CgiModule"]' -name lockItem -value true -PSPath iis:

    Related UI Task:UI Feature:"Modules" page

  35. [IIS] Change order Module elements and Revert To Inherit for a site level

    Case1: Move testmodule to bottom index

    # remove the target item and then re-create the item
    Remove-WebConfigurationProperty //modules -name collection -at @{name='testmodule';lockItem='true'}  -PSPath iis:
    
    Add-WebConfigurationProperty //modules -name collection -value @{name='testmodule';lockItem='true'}  -PSPath iis:

    Case2: Revert To Inherit for 'site' level

    Clear-WebConfiguration //modules -name -PSPath 'iis:sitesdefault web site'

    Related UI Task:UI Feature:"Modules" page

  36. [IIS] Get the list of worker processes and requests which is running on an Application Pool
    get-webrequest -Process 3644 -AppPool defaultapppool
    ### Get the process information of DefaultAppPool
    PS IIS:AppPoolsDefaultAppPoolWorkerProcesses> dir
    Process  State      Handles  Start TimeId
    -------- -----      -------  ----------
    3644     Running    310      7/24/2008 4:23:22 PM
    ### Call Get-WebRequest to get the list of requests using the process informationPS
    IIS:AppPoolsDefaultAppPoolWorkerProcesses> get-webrequest -Process 3644 -AppPool defaultapppool  requestId    : fe00000080000466connectionId : fe00000060000463verb         : GETurl          : /long.aspxsiteId       : 1
    ### Or, you can use GetRequsts() method:PS
    IIS:AppPoolsDefaultAppPoolWorkerProcesses> (get-item 3644).getrequests($null)  requestId    : fe00000080000469connectionId : fe00000060000463verb         : GETurl          : /long.aspxsiteId       : 1

    Related UI Task:UI Feature: "Worker Processes" page

Running Tomcat with IIS on Nano Server

$
0
0
  • Introduction
  • Setup
    • Step 1: prepare Nano server with IIS role and httpPlatformHandler
    • Step 2: install Tomcat on Nano Server
  • Configure settings
    • Step 3: configure server.xml of Tomcat
    • Step 4: configure httpPlatformHandler for Tomcat
    • Step 5: configure Default Web Site
  • Run
  • Troubleshoot

 

Introduction

 

This article shows how to set-up Tomcat and httpPlatformHandler with IIS of Nano server.

 

Setup

 

Step 1: prepare Nano server with IIS role and httpPlatformHandler

 

First you need to install IIS on Nano and then install httpPlatformHandler on your Nano server.

Installing IIS on Nano is already covered in the ariticle below, so I’ll skip those steps here for brevity.

Please notice that the article explains both "Installing IIS" and "Installing the ASP.NET Core Module (ANCM)".
You can skip installing the ASP.NET Core Module (ANCM) because ANCM is not required for running Tomcat on Nano server.

Once you installed IIS on your Nano server, now you are ready to install HttpPlatformHandler on your Nano server.

In order to install HttpPlatformHandler on your Nano server, you have to install it on your regular 64 bit(amd64) Windows machine first in order to get two files, one httpPlatoformHandler.dll and the other httpplatform_schema.xml, copy them to Nano server manually and configure required IIS configurations manually as well.

Here is how to do that step by step.

On a regula 64 bit Windows machine, go to this download page which is for HttpPlatformHandler and download X64 version msi file (httpPlatformHandler_amd64.msi) and execute it to install HttpPlatformHandler on the machine. After HttpPlatform is installed, locate the following two files and copy them to your Nano server onto the same directory.

%windir%\System32\inetsrv\HttpPlatformHandler.dll
%windir%\System32\inetsrv\config\schema\httpplatform_schema.xml

FYI, on purpose, I did not mention about %windir%\Syswow64\inetsrv\HttpPlatformHandler.dll because Nano server does not support 32 bit IIS module and we don't need to copy the 32 bit dll file on Syswow64 directory.

FYI, in case you don't know how to copy any file to your Nano server, I'd like to inform that you can use Copy-Item powershell cmdlet with -ToSession paramerter.
NOTE: in order to use Copy-Item cmdlet for that purpose, you need to configure TrustedHosts for powershell remoting as you did for making the remote powershell tab to your Nano server. 

Here is the example powershell script to copy the two files to a remote Nano server. Modify the ip address of Nano Server with the real one which is used by your Nano server and run it and you will be able to copy the two files to the rigth destination. 

$ip = "<IP address of Nano Server>" # For example, $ip = "10.127.67.20"
$user = "$ip\Administrator"  # supposing you know the password of administrator account on Nano server
$s = New-PSSession -ComputerName $ip -Credential $user
Copy-Item -ToSession $s -Path "$env:windir\System32\inetsrv\HttpPlatformHandler.dll" -Destination C:\windows\system32\inetsrv\
Copy-Item -ToSession $s -Path "$env:windir\System32\inetsrv\config\schema\httpplatform_schema.xml" -Destination C:\windows\system32\inetsrv\config\schema\

After copying the two files to your Nano server, open a remote powershell tab to your Nano server and run the following powershell cmdles to complete installing httpPlatformHandler on your Nano server: 

Import-Module IISAdministration 

Reset-IISServerManager -confirm:$false
$sm = Get-IISServerManager
$appHostconfig = $sm.GetApplicationHostConfiguration()
$section = $appHostconfig.GetSection("system.webServer/handlers")
$section.OverrideMode="Allow"
$sm.CommitChanges()

Reset-IISServerManager -confirm:$false
$sm = Get-IISServerManager
$appHostconfig = $sm.GetApplicationHostConfiguration()
$sectionHttpPlatform = $appHostConfig.RootSectionGroup.SectionGroups["system.webServer"].Sections.Add("httpPlatform")
$sectionHttpPlatform.OverrideModeDefault = "Allow"
$sm.CommitChanges()

Reset-IISServerManager -confirm:$false
$globalModules = Get-IISConfigSection "system.webServer/globalModules" | Get-IISConfigCollection
New-IISConfigCollectionElement $globalModules -ConfigAttribute @{"name"="httpPlatformHandler";"image"="%windir%\system32\inetsrv\httpPlatformHandler.dll"}
 
Reset-IISServerManager -confirm:$false
$modules = Get-IISConfigSection "system.webServer/modules" | Get-IISConfigCollection
New-IISConfigCollectionElement $modules -ConfigAttribute @{"name"="httpPlatformHandler"}

FYI, after running the powershell cmdelts, the c:\windows\system32\inetsrv\config\applicationhost.config in your Nano machine will be updated like this.

...

        <section name="httpPlatform" overrideModeDefault="Allow" />

    </sectionGroup>

</configSections>

...


    <add name="httpPlatformHandler" image="%windir%\system32\inetsrv\httpPlatformHandler.dll" />

</globalModules>

...


<add name="httpPlatformHandler" />

</modules>

...

Step 2: install Tomcat on Nano Server

 

In this step you will set-up JDK and Tomcat on your Nano server.

In order to install JDK to your Nano server, you have to install it on your regular Windows machine. You need a 64 bit OS because you will be using a 64bit JDK.

On a regular 64bit Windows machine where you can install JDK, go to this download page of JDK and download it.

 

http://www.oracle.com/technetwork/java/javase/downloads/index.html

 

You should download the latest build of Java SE Development Kit for Windows x64 platform.

The downloaded file name will be like "jdk-8u66-windows-x64.exe" if the latest JDK's version is "8u66".

Then install the JDK on the regular Windows OS machine. After installation is done, you will see the JDK installation directory has been created under "C:\Program Files\Java\jdk1.8.0_66" or a certain place you choose.

 

Now you need to actually install the JDK onto your Nano server machine.

The installation is very simple. You just need to copy the JDK directory from your regular Windows machine to a certain directory such as c:\ of your Nano server machine.

 

If you copied the JDK directory such as "jdk1.8.0_66" onto c:\ directory of Nano server machine, the directory structure should be like this.

 

[nano1]: PS C:\jdk1.8.0_66> dir

    Directory: C:\jdk1.8.0_66


Mode               LastWriteTime         Length Name                                                                                                             

----               -------------         ------ ----                                                                                                            

d-----         12/10/2015   4:52 PM               bin   

d-----         12/10/2015   4:52 PM               db    

d-----         12/10/2015   4:52 PM               include  

d-----         12/10/2015   4:52 PM               jre  

d-----         12/10/2015   4:53 PM               lib  

-a----       11/9/2015 11:09 AM           3244 COPYRIGHT                                                    

-a----         12/10/2015   4:44 PM       5104608 javafx-src.zip 

-a----         12/10/2015   4:44 PM            40 LICENSE  

-a----         12/10/2015   4:44 PM           159 README.html                                 

-a----         12/10/2015   4:44 PM           527 release 

-a----       11/9/2015 11:09 AM       21244088 src.zip                                                                                                       

-a----         12/10/2015   4:44 PM         110114 THIRDPARTYLICENSEREADME-JAVAFX.txt  

-a----         12/10/2015   4:44 PM         177094 THIRDPARTYLICENSEREADME.txt   

                                                                      

Go to this download page of Tomcat.

http://tomcat.apache.org/download-80.cgi (supposing you're going to install Tomcat v8.0).

 

Then download the "64-bit Windows zip" file. The downloaded file name will be like "apache-tomcat-8.0.30-windows-x64.zip".

Unzip the downloaded zip file and copy its content onto c:\ of your Nano server machine.

 

If you copied Tomcat directory such as "apache-tomcat-8.0.30" onto c:\ directory of Nano server machine, the directory structure should be like this.

[nano1]: PS C:\apache-tomcat-8.0.30> dir

    Directory: C:\apache-tomcat-8.0.30

Mode               LastWriteTime         Length Name                                                                                                              

----               -------------         ------ ----                                                                                                            

d-----         12/10/2015   5:22 PM               bin 

d-----         12/11/2015   2:24 PM               conf 

d-----         12/10/2015   5:22 PM               lib  

d-----         12/11/2015   1:58 PM               logs

d-----         12/10/2015   5:22 PM               temp 

d-----         12/11/2015   1:53 PM               webapps  

d-----         12/11/2015   2:24 PM               work 

-a----       12/9/2015   6:39 PM          58068 LICENSE 

-a----       12/9/2015   6:39 PM           1489 NOTICE  

-a----       12/9/2015   6:39 PM           6913 RELEASE-NOTES   

-a----       12/9/2015   6:39 PM         16671 RUNNING.txt    

 

Configure settings

 

Step 3: configure server.xml of Tomcat

 

Now you have to change the configuration file of Tomcat server which is c:\apatche-tomcat-8.0.30\conf\server.xml of your Nano server machine supposing your Tomcat directory is c:\apatche-tomcat-8.0.30.

The server.xml uses hardcoded value such as 8005 for shutdown and 8080 for startup. That should be changed to be the following:

 

FROM:

...

<Server port="8005" shutdown="SHUTDOWN">

...

<Connector port="8080" protocol="HTTP/1.1"

 

TO:

...

<Server port="-1" shutdown="SHUTDOWN">

...

<Connector port="${port.http}" protocol="HTTP/1.1"

...

 

As you can see, you need to change 8005 with -1 and 8080 with ${port.http}.

 

The value for ${port.http} will be set by httpFlatformHandler on runtime with an available TCP port number at that time. The value of the shutdown port, -1, is not actually used because the Tomcat server process runs as a child process of the IIS worker process, and it will be shut down automatically when the IIS worker process is shut down.

 

Step 4: configure httpPlatformHandler for Tomcat

 

Create a web.config file after creating a directory such as c:\inetpub\website1 and fill the file with the following content in order to configure httpFlatformHandler for Tomcat.

NOTE: This sample web.config has hardcoded values of C:\apache-tomcat-8.0.30, c:\jdk1.8.0_66 and C:\inetpub\website1. You have to adjust those values to match your Nano server environment. While adjusting values, make sure every value is pointing valid existing directory path. 

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

  <system.webServer>

    <handlers>

       <add name="httpplatformhandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" />

    </handlers>

    <httpPlatform processPath="C:\apache-tomcat-8.0.30\bin\startup.bat" arguments="" stdoutLogEnabled="true" stdoutLogFile="\\?C:\inetpub\website1\log.txt">

       <environmentVariables>

         <environmentVariable name="JRE_HOME" value="c:\jdk1.8.0_66" />

         <environmentVariable name="CATALINA_OPTS" value="-Dport.http=%HTTP_PLATFORM_PORT%" />      

         <environmentVariable name="CATALINA_HOME" value="C:\apache-tomcat-8.0.30" />

       </environmentVariables>

    </httpPlatform>

    <directoryBrowse enabled="true" />

  </system.webServer>

</configuration>

 

I'd like to inform that the line enabling directoryBrowse is optional. If you enable it, it will be useful while troubleshooting. For example, you can temporarily remove the config sections of handlers and httpPlatform to check if the website works without httpFlatform.

 

Step 5: configure Default Web Site

 

Open applicationhost.config file which is placed in c:\windows\system32\inersrv\config and edit the physicalPath of Default Web Site with the "c:\inetpub\website1" where you created web.config file.

 

Run

 

Now you are ready to start. In this section you will learn how to verify Tomcat and create a sample web application.

 

Step 6: start http://<ComputerName>

 

Restart IIS services first. You can use the commands "Stop-Service was -Force -Confirm:$false" and "Start-Service w3svc".

Now you are ready start. On any client machine from which you can connect to your Nano server machine, open a web browser such as IE and browse http://<ComputerName> (NOTE: replace <ComputerName> with the computer name of your Nano server) and you will get this result if everything is okay.

Note: the first request will take some time because it takes some time to start Tomcat.

 

Step 7: add sample webapp and run http://<ComputerName>/sample

 

You can download a sample Java web application and install it onto your Tomcat directory.

Download the sample directory from https://tomcat.apache.org/tomcat-6.0-doc/appdev/sample/ and copy onto C:\apache-tomcat-8.0.30\webapps, after which a new directory such as C:\apache-tomcat-8.0.30\webapps\sample will be created.

Now, you are ready to test the sample web application with browsing http://<ComputerName>/sample.

 

Troubleshoot

Here are common mistakes I made which caused up to an error of 500 and how I fixed those issues. Check these thing if you run into similiar issue.

  1. Make sure the httpPlatform configuration section should be added inside the sectionGroup of "system.webServer", not "system.applicationHost"
  2. Make sure overrideModeDefault of the httpPlatform configuration section is set to "Allow"
  3. Make sure that the server.xml for the Tomcat server is configured correctly
  4. Make sure web.config is configured correctly, especially for directory paths
  5. You might need to restart IIS services after making configuration changes in order to apply the change
  6. You might need to restart your web browser with clearing cached result to see the updated result after making configuration changes

You might want to know how to run the Tomcat server on your regular (non-Nano) Windows machines in order to confirm that your downloaded Tomcat server  works well before installing it onto your Nano server machine.

After installing Tomcat server on regular Windows machine, run the following commands to start Tomcatserver on regular Windows machine:

set JRE_HOME=%programfiles%\Java\jdk1.8.0_66

set CATALINA_OPTS=-Dport.http=1234

set CATALINA_HOME=C:\dev\javasites\bin\apache-tomcat-8.0.30

C:\dev\javasites\bin\apache-tomcat-8.0.30\bin\startup.bat

After running this, you will see the Tomcat server running while using TCP port 1234.

Then, browse http://localhost:1234 and verify that you got the right result.

 

Running Wordpress with IIS and WinCache on Nano Server

$
0
0
  • Introduction
  • Setup Nano server
    • Step 1: prepare Nano server with IIS role
    • Step 2: expand disk size
  • Setup PHP on Nano server
    • Step 3: install PHP on Nano server
    • Step 4: install vcuntime140.dll to %windir%\system32 on Nano Server
    • Step 5: install IIS-Cgi and configure applicationhost.config for PHP
    • Step 6: verify if php is correctly configured
  • Setup Wordpress
    • Step 7: install MySQL on Nano server
    • Step 8: register MySql database server as a Windows service
    • Step 9: create a database for Wordpress
    • Step 10: configure PHP for MySQL
    • Step 11: install Wordpress package on Nano server
    • Step 12: configure Default Web Site
  • Run
  • Enhance PHP performance with WinCach
    • Step 14: Install WinCache
    • Step 15: Verify WinCache

 

Introduction

 

This article shows how to set-up Wordpress on IIS of Nano server.

 

Setup Nano server

 

You will prepare Nano server here.

 

Step 1: prepare Nano server with IIS role

 

First you need to install IIS on Nano and then install httpPlatformHandler on your Nano server.

Installing IIS on Nano is already covered in the ariticle below, so I’ll skip those steps here for brevity.

Please notice that the article explains both "Installing IIS" and "Installing the ASP.NET Core Module (ANCM)".
You can skip installing the ASP.NET Core Module (ANCM) because ANCM is not required for running Tomcat on Nano server.

Step 2: expand disk size of Nano server

 

If you use the default disk size of the Nano server image (default hard disk is 4GB), you have to expand the disk size. Otherwise, you will fail to install MySQL because there is not enough disk space.

 

You can check the current disk size with running "Get-Disk" command from Remote powershell tab.

[nano1]: PS C:\> Get-Disk

Number Friendly Name                                                                            Serial Number                     HealthStatus           OperationalStatus     Total Size Partition

                                                                                                                                                                                          Style    

------ -------------                                                                               -------------                     ------------       -----------------     ---------- ----------

0       Virtual HD                                                                                                                   Healthy             Online                     10 GB MBR      

 

If your disk size is 4 GB, shutdown your Nano server virtual machine and open the "Settings" dialog of your Nano server Virtual machine.

Then click the "Edit" button after selecting Hard Drive.

Select the "Expand" button, and set the new size with more than 10 GB. Click the "Finish" button to apply the change, and restart yocd\cdur Nano server virtual machine.

 

Setup PHP on Nano server

 

Wordpress requires PHP. Here you will learn how to install PHP on Nano server machine.

 

Step 3: install PHP on Nano server

 

In this step, you will set-up PHP on your Nano server.

 

Go to http://windows.php.net/downloads/qa/ and download the latest 64 bit PHP such as php-7.0.1RC1-nts-Win32-VC14-x64.zip.

 

The file name php-7.0.1RC1-nts-Win32-VC14-x64.zip shows that its version is PHP 7.0.1 RC1 and it is built with Microsoft Visual C v14.

 

Unzip the downloaded zip file and copy the contents to a certain directory such as c:\php of your Nano server machine.

 

Your c:\php directory structure should be like this:

[nano1]: PS C:\php> dir

    Directory: C:\php

Mode               LastWriteTime         Length Name

----               -------------         ------ ----     

d-----         12/14/2015   1:55 PM               dev    

d-----         12/14/2015   1:55 PM               ext   

d-----        12/14/2015   1:42 PM               extras   

d-----         12/14/2015   1:55 PM               lib                                                               

d-----         12/14/2015   1:55 PM               sasl2   

-a----         12/14/2015 11:47 AM         114688 deplister.exe     

-a----         12/14/2015 11:47 AM       1360384 glib-2.dll     

-a----         12/14/2015 11:47 AM         18432 gmodule-2.dll     

-a----         12/14/2015 11:47 AM       25048064 icudt56.dll       

-a----         12/14/2015 11:47 AM       2086912 icuin56.dll       

-a----         12/14/2015 11:47 AM         52224 icuio56.dll      

…                

 

Step 4: install vcruntime140.dll to %windir%\system32 on Nano Server

 

PHP depends on the vcruntime140.dll file. If the vcruntime140.dll is not available on your Nano server, PHP cannot be executed. The vcruntime140.dll is available on any 64 bit Windows machine where the latest Visual Studio is installed. So, what you should do is to find the vcruntime140.dll file and copy the file to %windir%\system32 of your Nano server machine and confirm the file is copied correctly.

 

After you copy the vcruntime140.dll correctly to your Nano server machine, you need to confirm whether running "php.exe -?" shows the correct result on your remote powershell tab as the below screenshot. If the file is not copied correctly to the right place, it will silently fail showing an empty result when you execute "php.exe -?" because it fails to load the vcruntime140.dll file.

[nano1]: PS C:\windows\system32> dir .\vcruntime140.dll

    Directory: C:\windows\system32

Mode               LastWriteTime         Length Name                                                                                                                                       

----               -------------         ------ ----                                                                                                                  

-a----       6/25/2015 11:15 PM         88752 vcruntime140.dll

 

[nano1]: PS C:\windows\system32> cd \php

 

[nano1]: PS C:\php> .\php.exe -?

Usage: php [options] [-f] <file> [--] [args...]

    php [options] -r <code> [--] [args...]

    php [options] [-B <begin_code>] -R <code> [-E <end_code>] [--] [args...]

    php [options] [-B <begin_code>] -F <file> [-E <end_code>] [--] [args...]

    php [options] -S <addr>:<port> [-t docroot]

    php [options] -- [args...]

    php [options] -a

 

  -a               Run interactively

-c <path>|<file> Look for php.ini file in this directory

  -n               No php.ini file will be used

-d foo[=bar]     Define INI entry foo with value 'bar'

  -e               Generate extended information for debugger/profiler

-f <file>       Parse and execute <file>.

  -h               This help

  -i               PHP information

  -l               Syntax check only (lint)

Step 5: install IIS-Cgi and configure applicationhost.config for PHP

 

In this step, you will install IIS-Cgi feature and update applicationhost.config to add the fastcgi module with the php installation directory path, c:\php.

Here is how to install IIS-Cgi feature. If you did not install the feature before, run the command below in order to install IIS-Cgi feature.

DISM.EXE /enable-feature /online /featureName:IIS-CGI /all

NOTE: If you see any error while running "DISM.EXE /enable-feature /online /featureName:IIS-CGI /all", try to run the same command again after running the following cmdlets on your Nano server, which is an work-around way of a known issue. 

Import-module iisadministration
Reset-IISServerManager -confirm:$false
$sm = Get-IISServerManager
$appHostconfig = $sm.GetApplicationHostConfiguration()
$section = $appHostconfig.GetSection("system.webServer/handlers")
$section.OverrideMode="Inherit"
$sm.CommitChanges()

Now, you are ready to configure applicationhost.config for PHP.

On the Nano server machine, open %windir%\system32\inetsrv\config\applicationhost.config and configure highlighted config settings as the following (NOTE: You should adjust the directory path value with the actual value of your Nano machine's environment):

 

<defaultDocument enabled="true">

           <files>

               <add value="index.php" />

 

       <fastCgi>

           <application fullPath="C:\PHP\PHP-CGI.EXE" maxInstances="0" instanceMaxRequests="10000">

               <environmentVariables>

                   <environmentVariable name="PHP_FCGI_MAX_REQUESTS" value="10000" />

                   <environmentVariable name="PHPRC" value="C:\PHP" />

               </environmentVariables>

           </application>

       </fastCgi>

 

...

           <add name="FastCgiModule" image="%windir%\System32\inetsrv\iisfcgi.dll" />

       </globalModules>

 

...

           <add name="FastCgiModule" lockItem="true" />

       </modules>

 

...

       <handlers accessPolicy="Read, Script">

          <!-- NOTE: place the following line of PHP-iisfcgi in the first line -->

           <add name="PHP-iisfcgi" path="*.php" verb="GET,HEAD,POST" modules="FastCgiModule" scriptProcessor="C:\PHP\PHP-CGI.EXE" resourceType="Either" requireAccess="Script" />  

...

You can update the above configuration settings with running following powershell commands on remote Powershell tab:  

import-module iisadministration

Reset-IISServerManager -Confirm:$false

Get-IISConfigSection system.webServer/defaultDocument | Get-IISConfigElement -ChildElementName files | Get-IISConfigCollection | New-IISConfigCollectionElement -ConfigAttribute @{"value"="index.php"}

Get-IISConfigSection system.webServer/fastCgi | Get-IISConfigCollection | New-IISConfigCollectionElement -ConfigAttribute @{"fullPath"="C:\PHP\PHP-CGI.EXE";"maxInstances"=0;"instanceMaxRequests"=10000}

Get-IISConfigSection system.webServer/fastCgi | Get-IISConfigCollection | Get-IISConfigCollectionElement -ConfigAttribute @{"fullPath"="C:\PHP\PHP-CGI.EXE"} | Get-IISConfigElement -ChildElementName environmentVariables | Get-IISConfigCollection | New-IISConfigCollectionElement -ConfigAttribute @{"name"="PHP_FCGI_MAX_REQUESTS";"value"="10000"}

Get-IISConfigSection system.webServer/fastCgi | Get-IISConfigCollection | Get-IISConfigCollectionElement -ConfigAttribute @{"fullPath"="C:\PHP\PHP-CGI.EXE"} | Get-IISConfigElement -ChildElementName environmentVariables | Get-IISConfigCollection | New-IISConfigCollectionElement -ConfigAttribute @{"name"="PHPRC";"value"="C:\PHP"}

Get-IISConfigSection system.webServer/handlers | Get-IISConfigCollection | New-IISConfigCollectionElement -ConfigAttribute @{"name"="PHP-iisfcgi";"path"="*.php";"verb"="GET,HEAD,POST";"modules"="FastCgiModule";"scriptProcessor"="C:\PHP\PHP-CGI.EXE";"resourceType"="Either";"requireAccess"="Script"} -AddAt 0

 

Step 6: verify if php is correctly configured

 

Before going further, let's check whether php is correctly installed and configured.

 

Create phpinfo.php on the root directory of the Default Web Site such as c:\inetpub\wwwroot with the following file content:

 

<?php

phpinfo();

?>

 

Open a web browser and send a request to http://<ComputerName>/phpinfo.php (NOTE: replace <ComputerName> with your Nano server's machine name) and verify that it shows the correct result of the phpinfo.php.

  

Setup Wordpress

 

Wordpress needs a database, and here, I will demonstrate how to install MySql on the Nano server and how to initialize it. Then, I will show how to install Wordpress.

 

Step 7: install MySQL on Nano server

 

In this step, you will setup MySQL on your Nano server.

 

Go to https://www.mysql.com/ and download the latest 64 bit MySQL such as mysql-5.6.26-winx64.zip.

 

Unzip the downloaded zip file and copy the contents to a directory such as c:\MySQL of your Nano server machine.

 

Your c:\mysql directory structure should be like this:

 

[nano1]: PS C:\MySql> dir

 

   Directory: C:\MySql

 

Mode               LastWriteTime         Length Name                                                                                                                                              

----               -------------         ------ ----                                                                                                                                              

d-----         12/14/2015   5:33 PM               bin    

d-----         12/14/2015   5:34 PM               data      

d-----         12/14/2015   5:34 PM              docs          

d-----         12/14/2015   5:34 PM               include                              

d-----         12/14/2015   5:35 PM               lib                                              

d-----         12/14/2015   5:45 PM               mysql-test       

d-----          9/22/2015   3:22 PM               scripts           

                                       

 

Step 8: register MySql database server as a Windows service

 

In this step you will setup MySQL on your Nano server.

Run "mysqld.exe --install" from c:\MySql\bin directory of your Nano server and restart the machine.

 

Here is the screenshot of running the "mysqld.exe --install" command to register MySql as a Windows service and to restart the machine:

[nano1]: PS C:\> cd .\MySql\bin

[nano1]: PS C:\MySql\bin> .\mysqld.exe --install

Service successfully installed.

 

[nano1]: PS C:\MySql\bin> Restart-Computer;Exit 

 

After machine has restarted, run "get-process" and you will see the mysqld process running.

 

Here is the screenshot which shows the mysqld process running:

[nano1]: PS C:\> get-process

 

Handles   NPM(K)   PM(K)     WS(K) VM(M)   CPU(s)       Id SI ProcessName                                                                                                                          

-------   ------   -----     ----- -----   ------       -- -- -----------                                                                                                                          

             6     640       1632 ...63     0.02     288   0 csrss                                                                                                                              

             5     832       3600 ...69     0.00     1080   0 EMT       

             0       0         4     0               0   0 Idle    

               16     2360      8676 ...87     0.13     344   0 lsass     

               15   585040     449588     626     0.33   228     0 mysqld       

 

Step 9: create a database for Wordpress

 

Run the following command from C:\MySql\bin directory in order to create a new database which will be used by Wordpress:

.\mysql.exe -u root -e "create database nanoserver1_wordpress"

 

This screenshot shows how to create a new database and list up existing databases. I assume you used an empty password for the "root" database user. Otherwise, you will have to specify the password as well.

[nano1]: PS C:\> cd .\MySql\bin

[nano1]: PS C:\MySql\bin> .\mysql.exe -u root -e "create database nanoserver1_wordpress"

[nano1]: PS C:\MySql\bin> .\mysql.exe -u root -e "show databases;"

Database

information_schema

mysql

nanoserver1_wordpress

performance_schema

test

 

Step 10: configure PHP for MySQL

 

Create a new php.ini file under c:\php directory with the following file content:

 

[PHP]

extension_dir=c:\php\ext

extension=php_mysqli.dll

 

This screenshot shows how I created the file with psedit and how I checked the file path.

[nano1]: PS C:\> cd .\php

[nano1]: PS C:\php> new-item php.ini

 

    Directory: C:\php

 

Mode               LastWriteTime         Length Name                                              

----               -------------         ------ ----                                  

-a----         12/14/2015   6:05 PM             0 php.ini            

 

[nano1]: PS C:\php> psedit php.ini

### Here you have to save the php.ini file with the above file content

[nano1]: PS C:\php> type .\php.ini

[PHP]

extension_dir=c:\php\ext

extension=php_mysqli.dll

 

[nano1]: PS C:\php> dir C:\php\ext\php_mysqli.dll

    Directory: C:\php\ext

Mode               LastWriteTime         Length Name                                                                                                                                              

----               -------------         ------ ----                                                      

-a----         12/14/2015 11:47 AM         131072 php_mysqli.dll    

 

Step 11: install Wordpress package on Nano server

 

In this step, you will install Wordpress on your Nano server.

Go to https://wordpress.org/ and download the latest package file such as wordpress-4.3.1.zip.

Unzip the downloaded zip file and copy the contents to a directory such as c:\wordpress of your Nano server machine.

 

Your c:\wordpress directory structure should be like this:

[nano1]: PS C:\wordpress> dir

    Directory: C:\wordpress

Mode               LastWriteTime         Length Name 

----               -------------         ------ ----                                                                                      

d-----         12/14/2015   6:11 PM               wp-admin   

d-----         12/14/2015   6:11 PM               wp-content                 

d-----         12/14/2015   6:12 PM              wp-includes 

-a----         9/3/2015   3:33 AM           418 index.php                          

-a----         9/3/2015   3:33 AM         19930 license.txt   

-a----       9/15/2015   2:26 PM           7360 readme.html       

-a----         9/3/2015   3:33 AM           4951 wp-activate.php  

 

Now create wp-config.php file on c:\wordpress directory with the following file content:

 

<?php

define('DB_NAME', 'nanoserver1_wordpress');

define('DB_USER', 'root');

define('DB_PASSWORD', '');

define('DB_HOST', 'localhost');

define('DB_CHARSET', 'utf8');

define('DB_COLLATE', '');

define('AUTH_KEY',         'put your unique phrase here');

define('SECURE_AUTH_KEY', 'put your unique phrase here');

define('LOGGED_IN_KEY',   'put your unique phrase here');

define('NONCE_KEY',      'put your unique phrase here');

define('AUTH_SALT',       'put your unique phrase here');

define('SECURE_AUTH_SALT', 'put your unique phrase here');

define('LOGGED_IN_SALT',   'put your unique phrase here');

define('NONCE_SALT',       'put your unique phrase here');

$table_prefix = 'wp_';

define('WP_DEBUG', false);

if ( !defined('ABSPATH') )

define('ABSPATH', dirname(__FILE__) . '/');

require_once(ABSPATH . 'wp-settings.php');

 

The screenshot below shows how I created the file with the psedit tool. It also shows the content of the file with the "type .\wp-config.php" command. 

[nano1]: PS C:\> cd .\wordpress

[nano1]: PS C:\wordpress> new-item wp-config.php

    Directory: C:\wordpress

Mode               LastWriteTime         Length Name                                                          

----               -------------         ------ ----                                                          

-a----         12/14/2015   6:19 PM             0 wp-config.php                                                  

                                                                                    

[nano1]: PS C:\wordpress> psedit .\wp-config.php

### Here you have to save the wp-config.php file with the above file content

[nano1]: PS C:\wordpress> type .\wp-config.php

<?php

define('DB_NAME', 'nanoserver1_wordpress');

define('DB_USER', 'root');

define('DB_PASSWORD', '');

define('DB_HOST', 'localhost');

define('DB_CHARSET', 'utf8');

define('DB_COLLATE', '');

define('AUTH_KEY',         'put your unique phrase here');

define('SECURE_AUTH_KEY', 'put your unique phrase here');

define('LOGGED_IN_KEY',   'put your unique phrase here');

define('NONCE_KEY',       'put your unique phrase here');

define('AUTH_SALT',       'put your unique phrase here');

define('SECURE_AUTH_SALT', 'put your unique phrase here');

define('LOGGED_IN_SALT',   'put your unique phrase here');

define('NONCE_SALT',       'put your unique phrase here');

$table_prefix = 'wp_';

define('WP_DEBUG', false);

if ( !defined('ABSPATH') )

define('ABSPATH', dirname(__FILE__) . '/');

require_once(ABSPATH . 'wp-settings.php');

 

[jhkim-nano1]: PS C:\wordpress>

 

Step 12: configure Default Web Site

 

Open the applicationhost.config file which is placed in c:\windows\system32\inersrv\config and edit the physicalPath of the Default Web Site with "c:\wordpress".

 

Run

 

Now you are ready to start. In this section you will learn how to initialize Wordpress and use it.

 

Step 13: start http://<ComputerName>/wp-admin/install.php

 

Restart IIS services first. You can use the commands "Stop-Service was -Force -Confirm:$false" and "Start-Service w3svc".

Now you are ready to start.

On any client machine from which you can connect to your Nano server machine, open a web browser such as IE and browse http://<ComputerName>/wp-admin/install.php (NOTE: replace <ComputerName> with the computer name of your Nano server) and you will see a page which shows the list of language names.  

Select "English (United States)" and click Continue and now you will see the Welcome page. Fill in the form as you want to and click the "Install Wordpress" button.

And you will see the "Success!" page which has the "Log In" button.

Click the "Log In" button.

Type the user name and password that you used in the previous steps and click the "Log In" button.

If everything is okay, you will get to the Word press page.

 

Enhance PHP performance with WinCache

 

If you want better performance for the Wordpress web site or any PHP web sites running on IIS, you should use WinCache.

Here I will show how to install WinCache on Nano server and verify how it works.

 

Step 14: Install WinCache

 

Go to http://sourceforge.net/projects/wincache/files/development/wincache-2.0.0.2-dev-7.0-nts-vc14-x64.exe/download and download the latest 64 bit WinCache.

The file name will be like wincache-2.0.0.2-dev-7.0-nts-vc14-x64.exe.

Execute the downloaded file in order to unzip files in it.

Assuming you have installed PHP on c:\php directory, copy php_wincache.dll onto c:\php\ext directory of your Nano machine.

Edit c:\php\php.ini and add the line below.

 

extension=php_wincache.dll

 

This screenshot shows how I verified that the file has been correctly copied.

[nano1]: PS C:\php> dir .\ext\php_wincache.dll

    Directory: C:\php\ext

Mode               LastWriteTime         Length Name                                                          

----               -------------         ------ ----                                                          

-a----         10/30/2015 12:02 PM         143360 php_wincache.dll   

 

[nano1]: PS C:\php> type .\php.ini

[PHP]

extension_dir=c:\php\ext

extension=php_mysqli.dll

extension=php_wincache.dll

 

[jhkim-nano1]: PS C:\php>

 

Step 15: Verify WinCache

 

One easy way to verify PHP and Wincache is to simply run "php.exe --ini" and make sure there is no error.

 

This screenshot shows the example of running ".\php.exe --ini".

[nano1]: PS C:\php> .\php.exe --ini

Configuration File (php.ini) Path: C:\Windows

Loaded Configuration File:         C:\php\php.ini

Scan for additional .ini files in: (none)

Additional .ini files parsed:     (none)

 

Another way to verify is to use wincache2.php, which is one of files installed by the WinCache.

Copy wincache2.php onto the root directory of your web site such as c:\wordpress. 

Edit wincache2.php and change the value of USE_AUTHENTICAITION with 0 like the following:

 

FROM:

...

define('USE_AUTHENTICATION', 1);

 

TO:

...

define('USE_AUTHENTICATION', 0);

 

If you don't change the value of USE_AUTHENTICATION, you will see some error message regarding authentication.

 

Okay, now you are ready to run the php file.

Open a web browser and browse http://<ComputerName>/wincache2.php (NOTE: replace <ComputerName> with your machine name).

You will see the “Windows Cache Extension for PHP – Statistics” page and that Wincache is working correctly on your Nano server machine.

 

How to use IISAdministration powershell cmdlets to configure IIS configuration settings

$
0
0

FYI, see the below blog first for the detailed information.

https://blogs.iis.net/bariscaglar/iisadministration-powershell-cmdlets-new-feature-in-windows-10-server-2016

 

If you use Configuration Editor, you can make IISPowershell cmdlets more easily. Configuration Editor is a good start point to make IISAdministration powershell script easily.

For example, if you want to add a new appSetting value to Default Web Site, you can generate a code for C# programming with Configuration Editor and you can convert the generated code to IISAdministration powshell cmdles because they are based on the same API.

Here is how to do that:

  1. Open Inetmgr.exe
  2. Select Default Web Site
  3. Go to Configuration Editor page
  4. Expand “Section:” dropdown and select “appSettings”
  5. Click the second column of “(Collection)” listview item
  6. Click “…” button and you will see “Collection Editor” dialog opened
  7. Click “Add” task on the right pane of the “Collection Editor” dialog
  8. Type “test” for the key property and “test2” for the value property and then close the “Collection Editor” dialog
  9. Click “Generate Script” task, and you will get the below code. Click “Cancel” task of Configuration Editor to ignore the change.

using System;

using System.Text;

using Microsoft.Web.Administration;

internal static class Sample {

   private static void Main() {

       using(ServerManager serverManager = new ServerManager()) {

           Configuration config = serverManager.GetWebConfiguration("Default Web Site");

           ConfigurationSection appSettingsSection = config.GetSection("appSettings");

           ConfigurationElementCollection appSettingsCollection = appSettingsSection.GetCollection();          

           ConfigurationElement addElement = appSettingsCollection.CreateElement("add");

             addElement["key"] = @"test";

             addElement["value"] = @"test2";

             appSettingsCollection.Add(addElement);

             serverManager.CommitChanges();

       }

   }

}

Now let’s convert the generated code into IISAdministration powshell cmdlet. Here is the example of the outcome.

Import-Module IISAdministration

Reset-IISServerManager -Confirm:$false

Start-IISCommitDelay

$webConfig = Get-IISConfigSection -SectionPath "appSettings" -CommitPath "Default Web Site"

$collection = Get-IISConfigCollection -ConfigElement $webConfig

New-IISConfigCollectionElement -ConfigCollection $collection -ConfigAttribute @{key='test';value='test2'}

Stop-IISCommitDelay

Remove-Module IISAdministration

 

More examples for your information.

Example 1. Configuring identityType and username together with a new attribute value for computer level.

Import-Module IISAdministration

Reset-IISServerManager -Confirm:$false

Start-IISCommitDelay

$appPoolConfigSection   = Get-IISConfigSection -SectionPath "system.applicationHost/applicationPools"

$appPoolDeefaultsElement = Get-IISConfigElement -ConfigElement $appPoolConfigSection -ChildElementName "applicationPoolDefaults"

$processModelElement     = Get-IISConfigElement -ConfigElement $appPoolDeefaultsElement -ChildElementName "processModel"

Set-IISConfigAttributeValue -ConfigElement $processModelElement -AttributeName "identityType" -AttributeValue "LocalSystem"

$anonymousAuthenticationConfigSection = Get-IISConfigSection -SectionPath "system.webServer/security/authentication/anonymousAuthentication"

Set-IISConfigAttributeValue -ConfigElement $anonymousAuthenticationConfigSection -AttributeName "userName" -AttributeValue ""

Stop-IISCommitDelay

Remove-Module IISAdministration

 

Example 2. Configuring IIS central certificate using IISAdministration

$sharePath = "$env:systemdrive\temp_share"

md $sharePath

 

$certStorePath = "Cert:\LocalMachine\My"

$thumbprint = New-SelfSignedCertificate -DnsName "explicit.one.ccs" -CertStoreLocation $certStorePath

$mypwd = ConvertTo-SecureString -String "xxx" -Force -AsPlainText

Export-PfxCertificate -FilePath "$sharePath\explicit.one.ccs.pfx" -Cert ($certStorePath + "\" + $thumbprint.Thumbprint) -Password $mypwd

 

$PrivateKeyPassword = "xxx"

$user = "administrator"

$passwordSecure = convertto-securestring iis6!dfu -asplaintext -force

$PrivateKeyPasswordSecure = convertto-securestring $PrivateKeyPassword -asplaintext -force

 

# Enable-IISCentralCertProvider

Enable-IISCentralCertProvider -CertStoreLocation $sharePath -UserName $user -Password $passwordSecure -PrivateKeyPassword $PrivateKeyPasswordSecure

 

Example 3. Configuring IIS Shared configuration

$sharedPath = "$env:systemdrive\temp_share2"

md $sharePath

$username = "$env:computername\administrator"

$password = convertto-securestring "password1&" -asplaintext -force

$keyEncryptionPassword = convertto-securestring "password2&" -asplaintext -force

Export-IISConfiguration -UserName $username -Password $password -PhysicalPath $sharedPath -KeyEncryptionPassword $keyEncryptionPassword -force

Enable-IISSharedConfig -UserName $username -Password $password -PhysicalPath $sharedPath -DontCopyRemoteKeys

 

Example 4. Set SSL Binding

$thumbprint = (dir Cert:\LocalMachine\WebHosting)[0].Thumbprint

$certificate = get-item ("Cert:\LocalMachine\WebHosting\" + $thumbprint)

$hash = $certificate.GetCertHash()

$sm = Get-IISServerManager

$sm.Sites["Default Web Site"].Bindings.Add("*:443:", $hash, "WebHosting", "None")

$sm.CommitChanges()

IIS Powershell User guide - Comparing representative IIS UI tasks

$
0
0
  1. [File System] Open Explorer window for Default Web Site's home directory
    $path=$(get-item 'iis:sitesdefault web site').physicalPath
    $path=[system.environment]::ExpandEnvironmentVariables($path)
    explorer $path

    Related UI Task:"Explorer"

  2. [File System] Open Explorer window for Default Web Site's home directory using "DirectoryName" property
    $path=$(get-item 'iis:sitesdefault web siteiisstart.htm').directoryName
    explorer $path

    Related UI Task:"Explorer"

  3. [File System] Create File and set file content programmatically
    $file=new-item demo.htm -type file
    set-content $file.FullName "Hey, dude!"

    Related UI Task:"Explorer"

  4. [File System] Set "Deny" for administrator user account for 'iisstart.htm' file and grant access permission for NTAccount
    $file=$(get-item "iis:sitesDefault Web Siteiisstart.htm ")
    $dacl=$file.GetAccessControl()
    $newRule=New-Object Security.AccessControl.FileSystemAccessRule Administrator, Modify, Deny
    $modified=$false
    $dacl.ModifyAccessRule("Add", $newRule, [ref]$modified)
    $file.SetAccessControl($dacl)
    $file.GetAccessControl().GetAccessRules($true, $true, [System.Security.Principal.NTAccount])

    Related UI Task:"Edit Permissions..."

  5. [Application Pool] Get the list of application pools
    dir iis:apppools

    Related UI Task:"Application Pools" treeview

  6. [Application Pool] Create a new pool
    New-Item iis:apppoolsdemoAppPool

    Or, you can use other task-based cmdlet(s) instead:

    New-AppPool demoAppPool

    NOTE: New-AppPool cannot use full path name such as “iis:appPoolsdemoAppPool” like other user-friendly-named cmdlets

    Related UI Task:"Add Application Pool..."

  7. [Application Pool] Rename an Application Pool
    Rename-Item iis:apppoolsdefaultapppool newAppPoolName

    Related UI Task:"Rename "

  8. [Application Pool] Remove an Application Pool
    Remove-Item iis:apppoolsdefaultapppool

    Or, you can use other task-based  cmdlet(s) instead:

    Remove-AppPool defaultapppool

    Related UI Task:"Remove "

  9. [Application Pool] Stop/Start/Recycle Application Pool
    Start-WebItem IIS:AppPoolsDefaultAppPoolStop-WebItem IIS:AppPoolsDefaultAppPoolRestart-WebItem IIS:AppPoolsDefaultAppPool

    Or, you can use other task-based cmdlet(s) instead:

    Start-AppPool DefaultAppPool
    Stop-AppPool DefaultAppPool
    Restart-AppPool DefaultAppPool

    Related UI Task:"Stop/Start/Recycle"

  10. [Application Pool] Get the current status of Application Pool
    Get-WebItemState iis:apppoolsdefaultapppool

    Or, you can use other task-based  cmdlet(s) instead:

    Get-AppPoolState defaultapppool

    Related UI Task:"Stop/Start/Recycle"

  11. [Application Pool] Get the list of application which is belonged to an Application Pool
    function ConvertFrom-ItemXPath($itemXpath)
    {
        $result = new-object psobject
    
        $tempString = $itemXPath.substring($itemXPath.IndexOf("@name"))
        add-member -in $result noteproperty Site $tempString.Split("'")[1]
    
        $tempString = $itemXPath.substring($itemXPath.IndexOf("@path"))
        add-member -in $result noteproperty Application $tempString.Split("'")[1]
        return $result
    }
    
    $applications = get-webconfiguration //application[@applicationPool]
    $applications | select itemXpath, applicationpool | foreach {if ($_.applicationPool -eq "DefaultAppPool") {ConvertFrom-ItemXPath ($_.itemXpath)}}
    

    Related UI Task:"View Applications"

  12. [Application Pool] Get Application Pool Default Settings
    $subsections=get-webconfiguration //applicationPoolDefaults//. -PSPATH iis:
    $subsections | foreach { $_.attributes | select name,value }
    PS IIS:\> $subsections = get-webconfiguration //applicationPoolDefaults//.
    PS IIS:\> $subsections | foreach { $_.attributes | select name,value }
    Name                                    Value
    ----                                    -----
    namequeueLength                         1000
    autoStart                               True
    enable32BitAppOnWin64                   False
    managedRuntimeVersion                   v2.0
    enableConfigurationOverride             True
    managedPipelineMode                     0
    passAnonymousToken                      True
    identityType                            2
    userName
    password
    loadUserProfile                         False
    manualGroupMembership                   False
    idleTimeout                             00:20:00
    maxProcesses                            1
    shutdownTimeLimit                       00:01:30
    startupTimeLimit                        00:01:30
    pingingEnabled                          True
    pingInterval                            00:00:30
    pingResponseTime                        00:01:30
    disallowOverlappingRotation             False
    disallowRotationOnConfigChange          False
    logEventOnRecycle                       137
    memory                                  0
    privateMemory                           0
    requests                                0
    time                                    1.05:00:00
    value                                   11:59:00
    value                                   11:32:00
    loadBalancerCapabilities                1
    orphanWorkerProcess                     False
    orphanActionExe
    orphanActionParams
    rapidFailProtection                     False
    rapidFailProtectionInterval             00:05:00
    rapidFailProtectionMaxCrashes           5
    autoShutdownExe
    autoShutdownParamslimit                 0
    action                                  0
    resetInterval                           00:05:00
    smpAffinitized                          False
    smpProcessorAffinityMask                4294967295

    logEventOnRecyle property value shows number value, which is not human-readable. You can get the text enum value by querying the specific property instead such as shown in the following:

    get-webconfiguration //applicationPoolDefaults/recycling/@logEventOnRecycle
    PS IIS:\> get-webconfiguration //applicationPoolDefaults/recycling/@logEventOnRecycleTime,Memory

    Related UI Task:"Set Application Pool Defaults..."

  13. [Application Pool] Set Application Pool Default Settings

    Case1: Setting queueLength, which is “property” type

    set-webconfigurationproperty /system.applicationHost/applicationPools/applicationPoolDefaults[1]/failure[1] -name rapidFailProtectionMaxCrashes -value 10
    # You could get the section path of the target property programmatically
    PS IIS:\> get-webconfiguration //*[@rapidFailProtectionMaxCrashes] | foreach {$_.itemXPath}/system.applicationHost/applicationPools/applicationPoolDefaults[1]/failure[1]/system.applicationHost/applicationPools/add[@name='DefaultAppPool']/failure[1]/system.applicationHost/applicationPools/add[@name='Classic .NET AppPool']/failure[1]
    # Set the property value with the section path
    PS IIS:\> set-webconfigurationproperty /system.applicationHost/applicationPools/applicationPoolDefaults[1]/failure[1] -name rapidFailProtectionMaxCrashes -value 10
    NOTE: “applicationPoolDefaults[1]/failure[1]” is equivalent to “applicationPoolDefaults/failure”.

    Case2: Setting schedule, which is “element” type (shown as “Specific Times” in UI)

    add-webconfiguration /system.applicationHost/applicationPools/applicationPoolDefaults/recycling/periodicRestart/schedule -value (New-TimeSpan -h 9 -m30)
    # Add new ‘Add’ element with a new-timespan value and add-webconfiguration cmdlet
    PS IIS:\> add-webconfiguration /system.applicationHost/applicationPools/applicationPoolDefaults/recycling/periodicRestart/schedule -value (New-TimeSpan -h 9 -m30) # Confirm the new value is added
    PS IIS:\> get-webconfiguration /system.applicationHost/applicationPools/applicationPoolDefaults/recycling/periodicRestart/schedule/add | select value value-----09:30:00

    Related UI Task:"Set Application Pool Defaults..."

  14. [Application Pool] Get configuration settings for a specific application pool
    $configSection="/system.applicationHost/applicationPools/add[@name='DefaultAppPool']//."
    $subsections=get-webconfiguration $configSection -PSPath iis:
    $subsections | foreach { $_.attributes | select name,value }

    Or, you can use “*” instead of the full config section path:

    $subsections=get-webconfiguration '//*[@name="DefaultAppPool"]//.' -PSPath iis:
    $subsections | foreach { $_.attributes | select name,value }

    Related UI Task:"Advanced Settings..."

  15. [Application Pool] Set configuration settings for a specific application pool

    Case1: Setting logEventOnRecycle, which is "enum property" type

    $configSection="/system.applicationHost/applicationPools/add[@name='DefaultAppPool']/recycling"
    set-webconfigurationproperty $configSection -name logEventOnRecycle -value 1 -PSPath iis:\

    NOTE: The value could be set with "Time" in the next version instead of 1 for the above example

    Related UI Task:"Advanced Settings..."

  16. [Application Pool] Get the list of application pools
    Dir iis:sites

    Related UI Task:"Sites" treeview

  17. [Sites] Create a new Web Site

    Case1: Create web site with single binding

    $binding=@{protocol="http";bindingInformation="*:80:hostname"}
    new-item "iis:sitesdemoSite" -type site –physicalPath c:demoSite -bindings $binding

    Case2: Create web site with multiple binding and specific id

    $binding=(@{protocol="http";bindingInformation="*:80:hostname"},@{protocol="http";bindingInformation="*:80:hostname2"})
    new-item "iis:sitesdemoSite" -type site -physicalPath c:demoSite -bindings $binding -id 555

    Or, you can use other task-based cmdlet(s) instead:

    New-WebSite -Name DemoSite -Port 80 -HostHeader hostname –PhysicalPath c:demoSite –ID 555
    New-WebBinding -Site DemoSite -Port 80 -IPAddress * -HostHeader hostname2

    Related UI Task:"Add Web Site..." wizard

  18. [Sites] Set bindings

    Case1: Create SSL Binding (127.0.0.1!443)

    $certObect=get-item cert:LocalMachineMyE48803C3A6DDC8F2BFE3D8B7B7D56BBA70270F92new-item IIS:SslBindings127.0.0.1!443 -value $certObect
    PS IIS:\> dir cert:\LocalMachine\My     Directory: Microsoft.PowerShell.Security\Certificate::LocalMachine\My
    Thumbprint                                Subject
    ----------                                -------
    E48803C3A6DDC8F2BFE3D8B7B7D56BBA70270F92  CN=WMSvc-JHKIM-WTT3
    
    PS IIS:\> $certObect = get-item cert:\LocalMachine\My\E48803C3A6DDC8F2BFE3D8B7B7D56BBA70270F92
    PS IIS:\> new-item IIS:\SslBindings\127.0.0.1!443 -value $certObect
    IP Address       Port Store            Sites
    ----------       ---- -----            -----
    127.0.0.1        443  My

    Case2: Set 'Bindings' property with multiple binding information including the SSL binding which was created above.

    $newBinding=(@{protocol="http";bindingInformation="127.0.0.1:80:normalSite"},@{protocol="https";bindingInformation="127.0.0.1:443:securedSite"})
    Set-itemproperty "IIS:SitesDefault Web Site" -name bindings -value $newBinding

    Or, you can use other task-based  cmdlet(s) instead:

    New-WebBinding -Site "Default Web Site" -Port 443 -IPAddress 127.0.0.1 -HostHeader securedSite

    NOTE: you can also use set-webconfiguration, set-webconfiguration or add-webconfigurationProperty.

    Set-Webconfiguration '/system.applicationHost/sites/site[@name="Default Web Site"]/bindings' -value $newBinding  -PSPath iis:
    Set-WebconfigurationProperty '/system.applicationHost/sites/site[@name="Default Web Site"]' -name bindings.collection -value $newBinding -at 0  -PSPath iis:
    Add-WebconfigurationProperty '/system.applicationHost/sites/site[@name="Default Web Site"]' -name bindings.collection -value @{protocol="https";bindingInformation="127.0.0.1:443:securedSite"} -at 0  -PSPath iis:

    Case3: Change a certain value of existing 'Bindings' property using other task-based  cmdlet.

    Set-WebBinding -Site "Default Web Site" -Port 443 -IPAddress 127.0.0.1 -HostHeader securedSite -name Port -value 444

    Case4: Removing binding information using other task-based  cmdlet.

    Remove-WebBinding -Site "Default Web Site" -Port 443 -IPAddress 127.0.0.1 -HostHeader securedSite

    Or, you can use Remove-WebConfigurationProperty

    Remove-WebconfigurationProperty '/system.applicationHost/sites/site[@name="Default Web Site"]' -name Bindings.collection -at @{protocol="https";bindingInformation="127.0.0.1:443:securedSite"}  -PSPath iis:

    Case5: Clear all the binding information of a certain web site

    Clear-Webconfiguration '/system.applicationHost/sites/site[@name="Default Web Site"]/bindings' -PSPath iis:

    NOTE: you can also use clear-itemproperty instead:

    Clear-ItemProperty 'iis:sitesDefault Web Site' -name bindings

    Related UI Task:"Bindings..."

  19. [Sites] Rename an Web Site
    Rename-Item "iis:sitesdefault web site" newWebSiteName

    Related UI Task:"Rename"

  20. [Sites] Remove an Web Site
    Remove-Item "iis:sitesdefault web site"

    Or, you can use other task-based  cmdlet(s) instead:

    Remove-WebSite " default web site"

    Related UI Task:"Remove "

  21. [Sites] Stop/Start/Restart Web Site
    Start-WebItem "IIS:SitesDefault Web Site"
    Stop-WebItem "IIS:SitesDefault Web Site"
    Restart-WebItem "IIS:SitesDefault Web Site"

    Or, you can use other task-based  cmdlet(s) instead:

    Start-WebSite "Default Web Site"
    Stop-WebSite "Default Web Site"
    Restart-WebSite "Default Web Site"

    Related UI Task:"Stop/Start/Restart"

  22. [Sites] Get the current status of Web Site
    Get-WebItemState "IIS:SitesDefault Web Site"

    Or, you can use other task-based  cmdlet(s) instead:

    Get-WebSiteState "Default Web Site"

    Related UI Task:"Stop/Start/Recycle"

  23. [Sites] Get Web Site Defaults Settings
    $subsections=get-webconfiguration //siteDefaults//. -PSPATH iis:
    $subsections | foreach { $_.attributes | select name,value }
    PS IIS:\> $subsections = get-webconfiguration //siteDefaults//. -PSPATH iis:\
    PS IIS:\> $subsections | foreach { $_.attributes | select name,value }
    Name                                    Value
    ----                                    -----
    nameid                                      0
    serverAutoStart                         True
    maxBandwidth                            4294967295
    maxConnections                          4294967295
    connectionTimeout                       00:02:00
    logExtFileFlags                         2215887
    customLogPluginClsidlogFormat                               2
    directory                               %SystemDrive%\inetpub\logs\LogFiles
    period                                  1
    truncateSize                            20971520
    localTimeRollover                       False
    enabled                                 True
    enabled                                 False
    directory                               %SystemDrive%\inetpub\logs\FailedReq...
    maxLogFiles                             50
    maxLogFileSizeKB                        512
    customActionsEnabled                    False
    allowUTF8                               True
    serverAutoStart                         True
    unauthenticatedTimeout                  30
    controlChannelTimeout                   120
    dataChannelTimeout                      30
    disableSocketPooling                    False
    serverListenBacklog                     60
    minBytesPerSecond                       240
    maxConnections                          4294967295
    resetOnMaxConnections                   False
    maxBandwidth                            4294967295
    matchClientAddressForPort               True
    matchClientAddressForPasv               True
    maxCommandLine                          4096
    allowUnlisted                           True
    serverCertHashserverCertStoreName       MY
    ssl128                                  False
    controlChannelPolicy                    1
    dataChannelPolicy                       1
    clientCertificatePolicy                 0
    useActiveDirectoryMapping               False
    validationFlags                         0
    revocationFreshnessTime                 00:00:00
    revocationUrlRetrievalTimeout           00:01:00
    enabled                                 False
    userName                                IUSRpassword
    defaultLogonDomain                      NT AUTHORITY
    logonMethod                             3
    enabled                                 False
    defaultLogonDomain
    logonMethod                             3
    enabled                                 False
    impersonationLevel                      1
    exitMessage
    greetingMessage
    bannerMessage
    maxClientsMessage
    suppressDefaultBanner                   False
    allowLocalDetailedErrors                True
    expandVariables                         False
    keepPartialUploads                      False
    allowReplaceOnRename                    False
    allowReadUploadsInProgress              False
    externalIp4Addressmode                  4
    adUserName
    adPasswordadCacheRefresh                00:01:00
    showFlags                               0
    virtualDirectoryTimeout                 5
    logExtFileFlags                         14716367
    directory                               D:\inetpub\logs\LogFiles
    period                                  1
    truncateSize                            20971520
    localTimeRollover                       False
    enabled                                 True
    selectiveLogging                        7

    Related UI Task:"Set Web Site Defaults..."

  24. [Sites] Set Web Site Default Settings

    Case1: Setting connectionTimeout

    set-webconfigurationproperty "/system.applicationHost/sites/siteDefaults[1]/limits[1]" -name connectionTimeout -value (New-TimeSpan -sec 130)
    # You could get the section path of the target property programmatically
    PS IIS:\> get-webconfiguration //*[@connectionTimeout] | foreach {$_.itemxpath}/system.applicationHost/webLimits/system.applicationHost/sites/siteDefaults[1]/limits[1]/system.applicationHost/sites/site[@name='Default Web Site' and @id='1']/limits[1]
    # Set the property value with the section path
    PS IIS:\> set-webconfigurationproperty "/system.applicationHost/sites/siteDefaults[1]/limits[1]" -name connectionTimeout -value (New-TimeSpan -sec 130)

    Related UI Task:"Set Web Site Defaults..."

  25. [Sites] Get configuration settings for a specific web site
    $configSection="/system.applicationHost/sites/site[@name='Default Web Site']//."
    $subsections=get-webconfiguration $configSection -PSPath iis:
    $subsections | foreach { $_.attributes | select name,value }

    Or, you can use “*” instead of the full config section path:

    $subsections=get-webconfiguration '//*[@name="Default Web Site"]//.' -PSPath iis:
    $subsections | foreach { $_.attributes | select name,value }

    Related UI Task:"Advanced Settings..."

  26. [Sites] Set configuration settings for a specific web site

    Case1: Setting maxLogFiles

    $configSection="/system.applicationHost/sites/site[@name='Default Web Site' and @id='1']/traceFailedRequestsLogging"
    set-webconfigurationproperty $configSection -name maxLogFiles -value 60 -PSPath iis:

    If you are trying to change basic properties, you could also use set-itemProperty as shown in the following:

    Case2: 'Application Pool' property

    Set-Itemproperty IIS:SitesDemoSite -name applicationPool -value demo AppPool

    Case3: 'Physical Path' property

    set-itemproperty IIS:SitesDemoSite -name physicalPath -value c:demoSite2

    Case4: 'username' property

    set-itemproperty IIS:SitesDemoSite -name userName -value newUserId

    Case5: 'password' property

    set-itemproperty IIS:SitesDemoSite -name password -value newPassword

     Related UI Task:"Advanced Settings..." 

  27. [Sites] Set Failed Request Tracing for a specific web site

    Case1: Enable Freb for a specific web site with setting maxLogFiles and directory

    $configSection="/system.applicationHost/sites/site[@name='Default Web Site' and @id='1']/traceFailedRequestsLogging"
    set-webconfigurationproperty $configSection -name maxLogFiles -value 60 -PSPath iis:
    set-webconfigurationproperty $configSection -name directory -value c:MyFailedReqLogFiles -PSPath iis:

    Or, you can use other task-based  cmdlet(s) instead:

    Enable-Freb -Site "default web site" -Directory "c:MyFailedReqLogFiles" -MaxLogFileSize 555

    Case2: Disable Freb for a specific web site

    $configSection="/system.applicationHost/sites/site[@name='Default Web Site' and @id='1']/traceFailedRequestsLogging"
    set-webconfigurationproperty $configSection -name enabled -value false -PSPath iis:

    Or, you can use other task-based  cmdlet(s) instead:

    Disable-Freb -Site "default web site"

    Case3: Clear Freb data for a specific web site

    If you use Enable-Freb, it creates following default setting of Freb settings for the specified sites. We can clear them by this way.

    <?xml version="1.0" encoding="UTF-8"?><configuration>    <system.webServer>        <tracing>            <traceFailedRequests>                <add path="*">                    <traceAreas>                        <add provider="WWW Server" areas="Authentication,Security,Filter,StaticFile,CGI,Compression,Cache,RequestNotifications,Module" verbosity="Verbose" />                        <add provider="ASP" verbosity="Verbose" />                        <add provider="ISAPI Extension" verbosity="Verbose" />                        <add provider="ASPNET" areas="Infrastructure,Module,Page,AppServices" verbosity="Verbose" />                    </traceAreas>                    <failureDefinitions timeTaken="00:00:30" statusCodes="500" verbosity="Warning" />                </add>            </traceFailedRequests>        </tracing>    </system.webServer></configuration>
    Clear-WebConfiguration /system.webServer/tracing/traceFailedRequests -PSPath "iis:sitesdefault web site"

    Or, you can use other task-based  cmdlet(s) instead:

    Clear-FrebData -Site "default web site"

    Related UI Task:"Advanced Settings..."

  28. [Management] Read default feature Delegation settings

    Case1: Dump all sectionGroups

    get-webconfigurationproperty / -name sectiongroups

    Case2: Dump specific sectionGroup such as "system.applicationHost"

    get-webconfigurationproperty / -name sectiongroups["system.applicationHost"]

    Case3: Dump all sections under "/" group

    get-webconfigurationproperty / -name Sections

    NOTE: You will see empty value because IIS configuration system does not have section under "root" level by default

    Case4: Dump all sections under specific sectionGroup such as "system.webServer"

    $sections=get-webconfigurationproperty /system.webserver -name Sections
    $sections | select Name,OverrideModeDefault
    PS IIS:\> $sections = get-webconfigurationproperty /system.webserver -name Sections
    PS IIS:\> $sections | select Name,OverrideModeDefault
    Name                                                        OverrideModeDefault
    ----                                                        -------------------
    httpProtocol                                                Allow
    httpErrors                                                  Deny
    httpRedirect                                                Allow
    globalModules                                               Deny
    cgi                                                         Deny
    serverRuntime                                               Deny
    directoryBrowse                                             Allow
    urlCompression                                              Allow
    httpLogging                                                 Deny
    modules                                                     Deny
    odbcLogging                                                 Deny
    validation                                                  Allow
    fastCgi                                                     Deny
    handlers                                                    Deny
    httpTracing                                                 Deny
    staticContent                                               Allow
    isapiFilters                                                Deny
    defaultDocument                                             Allow
    asp                                                         Deny
    httpCompression                                             Deny
    serverSideInclude                                           Deny
    caching                                                     Allow

    NOTE: Now you can see the default override mode for "ASP" config section is deny, which means we can configure ASP related properties only for 'server' level

    Related UI Task:UI Feature: "Feature Delegation" page

  29. [Management] Add/Remove customized IIS config section

    Case1: Add "myGroup" sectiongroup under root

    add-webconfigurationproperty / -name SectionGroups -value myGroup

    Case2: Add "mySection" section under the myGroup sectiongroup which was created above

    add-webconfigurationproperty /myGroup -name Sections -value mySection

    Case3: Set OverrideModeDefault for the newly created section, "mySection"

    set-webconfigurationproperty /myGroup -name Sections["mySection"].OverrideModeDefault -value Deny

    Case4: Set AllowDefinition for the newly created section, "mySection"

    set-webconfigurationproperty /myGroup -name Sections["mySection"].AllowDefinition -value AppHostOnly

    Case5: Set AllowLocation for the newly created section, "mySection"

    set-webconfigurationproperty /myGroup -name Sections["mySection"].AllowLocation -value false

    Case6: Remove the "mySection" section which were created above

    remove-webconfigurationproperty /myGroup -name Sections -at mySection

    Case7: Remove the "myGroup" sectiongroup which were created above

    remove-webconfigurationproperty / -name SectionGroups -at myGroup

    Related UI Task:UI Feature: UI has no related task for this.

  30. [Management] Configure Feature Delegation related settings

    NOTE: Before changing delegation setting of a config section, you would need to remove previously configured properties and elements of the section and re-configure them again after the delegation setting is updated.

    This is an example of how to remove ASP sections using clear-webconfiguration cmdlet:

    clear-webconfiguration /system.webServer/asp -pspath MACHINE/WEBROOT/A
    PPHOST/testSite
    clear-webconfiguration /system.webServer/asp -pspath MACHINE/WEBROOT/A
    PPHOST
    # Get the list of previously configured items using -recurse option
    PS IIS:\> get-webconfiguration //asp -Recurse
    SectionPath                             PSPath
    -----------                             ------
    /system.webServer/asp                   MACHINE/WEBROOT/APPHOST/system.webServer/asp                   MACHINE/WEBROOT/APPHOST/testSite
    # Clear those items using clear-webconfiguration
    PS IIS:\> clear-webconfiguration /system.webServer/asp -pspath MACHINE/WEBROOT/APPHOST/testSitePS IIS:\> clear-webconfiguration /system.webServer/asp -pspath MACHINE/WEBROOT/APPHOST

    Case1: Read the current Delegation setting of ASP feature for 'server' level

    get-webconfiguration //asp iis: | select OverrideMode
    PS IIS:\> get-webconfiguration //asp iis:\ | select
    OverrideMode
    OverrideMode------------Inherit

    NOTE: The value "inherit" means it uses the default override mode and it is actually "Deny" in the default IIS configuration

    Case2: Set "Read-Write" for ASP feature for 'server' level

    set-webconfiguration //asp -metadata overrideMode -value Allow -PSPath iis:

    Case3: Set "Not Delegated" for ASP feature for 'server' level

    NOTE: "Not Delegated" task is only applicable to IIS UI world. Please use "Read Only" which is explained below.

    Case4: Set "Read Only" for ASP feature for 'server' level

    set-webconfiguration //asp -metadata overrideMode -value Deny -PSPath iis:

    Case5: Set "Reset to Inherited" for ASP feature for 'server' level

    set-webconfiguration //asp -metadata overrideMode -value Inherit -PSPath iis:

    Case6: Change Delegation settings for 'site' level

    set-webconfiguration //asp -metadata overrideMode -value Inherit -PSPath "iis:sitesdefault web site"

    Case7: Change Delegation settings for 'site' level using location

    set-webconfiguration //asp -metadata overrideMode -value Inherit -PSPath "iis:sites" -Location "default web site"

    Related UI Task:UI Feature: "Feature Delegation" page

  31. [IIS] Configure Clasic ASP properties

    Case1: Read all ASP settings from 'server' level

    $subsections=get-webconfiguration //asp//. -PSPATH iis:
    $subsections | foreach { $_.attributes | select name,value }

    Case2: Read all ASP settings from 'web site' level such as "Default Web Site"

    $subsections=get-webconfiguration //asp//. -PSPATH "iis:sitesdefault web site"
    $subsections | foreach { $_.attributes | select name,value }

    Case3: Read all ASP settings from 'web application' level such as "DemoApplication "

    $subsections=get-webconfiguration //asp//. -PSPATH "iis:sitesdefault web sitedemoapplication"
    $subsections | foreach { $_.attributes | select name,value }

    Case4: Read all ASP settings from 'file' level which is under an Web Site

    $subsections=get-webconfiguration //asp//. -PSPATH "iis:sitesdefault web site" -location iisstart.htm
    $subsections | foreach { $_.attributes | select name,value }

    Case5: Write an ASP setting, keepSessionIdSecure, for 'server' level

    set-webconfigurationproperty "/system.webServer/asp/session[1]" -name keepSessionIdSecure -value true -PSPath iis:
    # You could get the section path of the target property programmaticallyPS IIS:> get-webconfiguration //*[@keepSessionIdSecure] | foreach {$_.itemxpath}/system.webServer/asp/session[1]
    # Set the property value with the section path
    PS IIS:> set-webconfigurationproperty "/system.webServer/asp/session[1]" -name keepSessionIdSecure -value true -PSPath iis:

    Case6: Write an ASP setting, keepSessionIdSecure, for 'site' level

    set-webconfigurationproperty "/system.webServer/asp/session[1]" -name keepSessionIdSecure -value true -PSPath "iis:sitesdefault web site"

    Case5: Write an ASP setting, keepSessionIdSecure, for 'file' level which is under an Web Site

    set-webconfigurationproperty "/system.webServer/asp/session[1]" -name keepSessionIdSecure -value true -PSPath "iis:sitesdefault web site" -location iisstart.htm

     Related UI Task:UI Feature: "ASP" page 

  32. [IIS] Configure Authentication properties

    Case1: List all of authentications and from 'server' level

    get-webconfiguration /system.webServer/security/authentication/*[@enabled] -PSPath iis: | select ItemXPath,enabled

    Case2: List all of authentications and from 'site' level

    get-webconfiguration /system.webServer/security/authentication/*[@enabled] -PSPath "iis:sitesdefault web site"| select ItemXPath,enabled

    NOTE: You can also get from other levels adjusting the value -PSPath and -Location parameter values

    Case3: Get all of Anonymous authentication properties from 'server' level

    $attributes=(Get-WebConfiguration /system.webServer/security/authentication/anonymousAuthentication -PSPath iis:).attributes
    $attributes | select name,value

    NOTE: You can also get from other levels adjusting the value -PSPath and -Location parameter values

    Case4: Change userName property for Anonymous authentication properties from 'server' level

    Set-WebConfigurationproperty system.webServer/security/authentication/anonymousAuthentication -name userName -value "" -PSPath iis:

    NOTE: You can also set for other levels adjusting the value -PSPath and -Location parameter values

    Related UI Task:UI Feature: "Authentication" page

  33. [IIS] Configure Module elements and properties which are configured in globalModules section

    Case1: List all native modules

    (Get-WebConfiguration //globalmodules).collection -PSPath iis:

    Case2: Add a new native modue at the bottom index of the existing modules

    Add-WebConfigurationProperty //globalmodules -name collection -value @{name='testmodule';image='c:test.dll'} -PSPath iis:

    Or, you can use other task-based  cmdlet(s) instead:

    New-WebModule -Name testmodule -Image c:test.dll -Precondition "integratedMode"

    Case3: Add a new native modue at the top index of the existing modules

    Add-WebConfigurationProperty //globalmodules -name collection -value @{name='testmodule';image='c:test.dll'} -at 0 -PSPath iis:

    Case4: Remove a native modue with a number index value

    Remove-WebConfigurationProperty //globalmodules -name collection -at 0 -PSPath iis:

    Case5: Remove a native modue with a hashtable index value

    Remove-WebConfigurationProperty //globalmodules -name collection -at @{name='testmodule';image='c:test.dll'} -PSPath iis:

    Or, you can use other task-based  cmdlet(s) instead:

    Remove-WebModule -Name testmodule

    Case6: Get the attributes for a specific module

    $modules=(get-webconfiguration //globalmodules -PSPath iis:).collection
    $modules | foreach {if ($_.name -eq "cgiModule") { $_.attributes | select name, value}}

    Case7: Change an attribute value for a specific module

    Get-Webconfigurationproperty '//globalmodules/add[@name="CgiModule"]' -name image -PSPath iis:
    Set-Webconfigurationproperty '//globalmodules/add[@name="CgiModule"]' -name image -value %windir%System32inetsrvcgi.dll -PSPath iis:

    Related UI Task:UI Feature: "Modules" page

  34. [IIS] Configure Module elements and properties

    Case1: Enable/Disable a native modue

    Add-WebConfigurationProperty //modules -name collection -value @{name='testmodule';lockItem='true'}  -at 0 -PSPath iis:

    Or, you can use other task-based  cmdlet(s) instead:

    Enable-WebModule -Name testModule

    Case2: Add a new managedModule

    Add-WebConfigurationProperty //modules -name collection -value @{name='newManagedModule';type='Microsoft.IIS.DemoModule'}  -PSPath iis:

    Or, you can use other task-based  cmdlet(s) instead:

    New-Managedwebmodule -name newManagedModule -Type Microsoft.IIS.DemoModule

    Case3: Disable module by removing the module element from the <modules> section

    Remove-WebConfigurationProperty //modules -name collection -at @{name='testmodule';lockItem='true'}  -PSPath iis:

    Or, you can use other task-based  cmdlet(s) instead:

    Disable-WebModule -Name testModule

    Case4: List all of enabled modules from 'server' level

    (get-webconfiguration //modules -PSPath iis:).collection -PSPath iis:

    Or, you can use other task-based  cmdlet(s) instead:

    Get-WebModule -PSPath iis: -enabled

    Case5: Get the attributes for a specific module

    $modules=(get-webconfiguration //modules -PSPath iis:).collection
    $modules | foreach {if ($_.name -eq "cgiModule") { $_.attributes | select name, value}}

    Case6: Change an attribute value for a specific module

    Get-Webconfigurationproperty '//modules/add[@name="CgiModule"]' -name lockItem -PSPath iis:
    Set-Webconfigurationproperty '//modules/add[@name="CgiModule"]' -name lockItem -value true -PSPath iis:

    Related UI Task:UI Feature:"Modules" page

  35. [IIS] Change order Module elements and Revert To Inherit for a site level

    Case1: Move testmodule to bottom index

    # remove the target item and then re-create the item
    Remove-WebConfigurationProperty //modules -name collection -at @{name='testmodule';lockItem='true'}  -PSPath iis:
    
    Add-WebConfigurationProperty //modules -name collection -value @{name='testmodule';lockItem='true'}  -PSPath iis:

    Case2: Revert To Inherit for 'site' level

    Clear-WebConfiguration //modules -name -PSPath 'iis:sitesdefault web site'

    Related UI Task:UI Feature:"Modules" page

  36. [IIS] Get the list of worker processes and requests which is running on an Application Pool
    get-webrequest -Process 3644 -AppPool defaultapppool
    ### Get the process information of DefaultAppPool
    PS IIS:AppPoolsDefaultAppPoolWorkerProcesses> dir
    Process  State      Handles  Start TimeId
    -------- -----      -------  ----------
    3644     Running    310      7/24/2008 4:23:22 PM
    ### Call Get-WebRequest to get the list of requests using the process informationPS
    IIS:AppPoolsDefaultAppPoolWorkerProcesses> get-webrequest -Process 3644 -AppPool defaultapppool  requestId    : fe00000080000466connectionId : fe00000060000463verb         : GETurl          : /long.aspxsiteId       : 1
    ### Or, you can use GetRequsts() method:PS
    IIS:AppPoolsDefaultAppPoolWorkerProcesses> (get-item 3644).getrequests($null)  requestId    : fe00000080000469connectionId : fe00000060000463verb         : GETurl          : /long.aspxsiteId       : 1

    Related UI Task:UI Feature: "Worker Processes" page

Developing IIS Native module

$
0
0

I have started to learn IIS Native API (C++) and hope to share what I have learned. This blog is targeting for beginner programmers who want to develop IIS native module in C++ for the first time.

What I will cover here

  • Understanding Global Module/Module/Handler
  • Quick reference of IIS Native API 
  • IIS Core system 

Understanding Global Module/Module/Handler

In order to learn IIS native API, I tried to create a small module with various sample codes and found some cases of not working. In the explanation of the popular example module, I had learned that I needed to register the module onto both <globalModules> and <modules> section. And it worked with no question.

  • TIP
    • My first module did not work because I complied the module as x86 version and wanted to make it run on amd64 bit machine. The problem was solved with compiling the module as 64 bit compilation)
    • Another mistake happened when I used the full path of my module dll file which is created by Visual Studio without access permission. I had to give the access permission for the users group for the directory to solve the error such as "The Module DLL c:workIISNativeModuleDebugMyModule.dll failed to load. The data is the error." which was shown in the event viewer.

My first module was to subscribe a single global level event such as GL_PRE_BEGIN_REQUEST and it worked in that way. And soon I realized the module works even though I removed the line of module from the <modules> section and I realized that if the module needs to subscribe only global level events, we don't need to register module onto <modules> section. This is how I learned the difference between module and global module in configuration wide.

I also tried to create another module which subscribes a single request level event such as RQ_EXECUTE_REQUEST_HANDLER. But this time, the module did not work even though I registered in the both <globalModules> and <modules> section.
I realized that actually I had made a handler module even though I thought I was making an ordinary module and I had to configure addional thing. Handler module is a special module which subscribes only the RQ_EXECUTE_REQUEST_HANDLER event. So, so the problem had to be solved by registering the module to <handlers> section.

But, I ran into another problem after I put my module, "TestModule", at the end of the value of modules attribute like this.

            <add name="StaticFile" path="*" verb="*" modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule, TestModule" resourceType="Either" requireAccess="Read" />

When I sent a request but the module was not invoked. And the problem was solved by changing the order of the module names like this.

            <add name="StaticFile" path="*" verb="*" modules=" TestModule ,StaticFileModule,DefaultDocumentModule,DirectoryListingModule" resourceType="Either" requireAccess="Read" />

That means, if there are multiple modules in a single handler item such as the above case, the previous modules can determine to make the next module run or not. And that's why my module was not picked up.

If you want to know more about this topic, refer to http://blogs.msdn.com/b/tmarq/archive/2007/08/30/iis-7-0-asp-net-pipelines-modules-handlers-and-preconditions.aspx.


Quick reference of IIS Native API

While I read MSDN, the number of classes/interfaces/struct/constants made me confused and overwhelmed. So, to get rid of the complexity, I tried to summarize the relationship between each interfaces and event handlers. After that, I felt it was not that complicated actually. Here is my version of summurized set of API, which I attached here for you to find the overal view of whole API sets.

1) Classes which are implemented in global or regular module (or handler module)

  • CGlobalModule, which is for global module
  • IHttpModuleFactory, which is a class factory of regular module
  • CHttpModule, which is for regular module

2) The order of creating the class objects

  • All objects should be created when RegisterModule() function, which is the unique exported DLL function of the module
  • CGlobalModule object is created at the heap memory and then its pointer is passed to IIS worker process by calling SetRequestNotifications() function
  • IHttpModuleFactory object is also created at the heap memory and then its pointer is passed to IIS worker process by calling SetGlobalNotifications() function
  • HttpModule object is created when IHttpModuleFactory object's GetHttpModule() function is called by IIS worker process
  • NOTE:
  • a. When GetHttpModule() is called, which happens for once for every request, we should create the HttpModule object every time and the object should be deleted if it was created in the heap memory when each request life cycle is finished
  • b. If you want to create a the module in heap, not stack memory, you can use IModuleAllocator interface to allocate memory of request pool
  • c. CGlobalModule event handler functions

3) Handler function name ant its event provider type

  • OnGlobalApplicationPreload
    • IGlobalApplicationPreloadProvider
  • OnGlobalApplicationResolveModules
    • IHttpApplicationResolveModulesProvider
  • OnGlobalApplicationStart
    • IHttpApplicationStartProvider
  • OnGlobalApplicationStop
    • IHttpApplicationStopProvider
  • OnGlobalCacheCleanup
    • void
  • OnGlobalCacheOperation
    • ICacheProvider
  • OnGlobalConfigurationChange
    • IGlobalConfigurationChangeProvider
  • OnGlobalCustomNotification
    • ICustomNotificationProvider
  • OnGlobalFileChange
    • IGlobalFileChangeProvider
  • OnGlobalHealthCheck
    • void
  • OnGlobalPreBeginRequest
    • IPreBeginRequestProvider
  • OnGlobalRSCAQuery
    • IGlobalRSCAQueryProvider
  • OnGlobalStopListening
    • IGlobalStopListeningProvider
  • OnGlobalThreadCleanup
    • IGlobalThreadCleanupProvider
  • OnGlobalTraceEvent
    • IGlobalTraceEventProvider
  • OnGlobalTerminate
    • void
  • Return value which are applied to all event handlers
    • GL_NOTIFICATION_CONTINUE
    • GL_NOTIFICATION_HANDLED, which indicates to stop IIS pipeline

4) CHttpModule event handler functions

  • Handler function name ant its event provider type
    • OnAcquireRequestState
      • OnPostAcquireRequestState
    • OnAsyncCompletion
    • OnAuthenticateRequest  (IAuthenticationProvider)
      • OnPostAuthenticateRequest
    • OnAuthorizeRequest
      • OnPostAuthorizeRequest
    • OnBeginRequest
      • OnPostBeginRequest
        • OnPostEndRequest
    • OnCustomRequestNotification (ICustomNotificationProvider)
    • OnEndRequest
    • OnExecuteRequestHandler
      • OnPostExecuteRequestHandler
    • OnLogRequest
      • OnPostLogRequest
    • OnMapPath (IMapPathProvider)
    • OnMapRequestHandler
      • OnPostMapRequest
    • OnPreExecuteRequestHandler
      • OnPostPreExecuteRequestHandler
    • OnReleaseRequestState
      • OnPostReleaseRequestState
    • OnResolveReuqestCache
      • OnPostResolveRequestCache
    • OnUpdateRequestCache
      • OnPostUpdateRequestCache
    • OnReadEntity (IReadEntityProvider)
    • OnSendResponse (ISendResponseProvider)
  • Return value which are applied to all event handlers
    • RQ_NOTIFICATION_CONTINUE
    • RQ_NOTIFICATION_FINISH, which indicates to stop IIS pipeline from request level
    • RQ_NOTIFICATION_PENDING, which indicates to stop IIS pipeline temporarily while module's executing its own task asynchronously.  There are two ways to do this such as using IHttpContext::ExecuteRequest and OnAyncCompletion() and IHttpContext::PostCompletion()

5) IHttpEventProvider and derived interfaces

  • IHttpEventProvider
    • IAuthenticationProvider
    • ICacheProvider
      • IHttpCacheKey  <==GetCacheKey()
        • IFileKey
        • IHttpTokenKey
        • IUriKey
      • IHttpCacheSpecificData  <==GetCacheRecord()
        • IHttpTokenEntry
    • ICustomNotificationProvider
    • IGlobalApplicationPreloadProvider
      • IGlobalApplicationPreloadProvider2
    • IGlobalConfigurationChangeProvider
    • IGlobalFileChangeProvider
      • IHttpFileMonitor  <==GetFileMonitor()
    • IGlobalRscaQueryProvider
    • IGlobalStopListeningProvider
    • IGlobalThreadCleanupProvider
    • IGlobalTraceEventProvider
    • IHttpApplicationProvider
    • IHttpApplicationResolveModulesProvider
    • IPreBeginRequestProvider
    • ISendResponseProvider
    • IMapHandlerProvider
    • IMapPathProvider
    • IReadEntityProvider
    • IHttpApplicationStartProvider

6) Relationship between Interfaces

  • IHttpCompletionInfo  <==CHttpModule::OnAsyncCompletion()
    • IHttpCompletionInfo2
  • IHttpContext
    •  IHttpApplication  <==GetApplication()
      • IHttpApplication2
    • IHttpConnection <==GetConnection()
    • IHttpFileInfo   <==GetFileInfo()
    • IMetadataInfo   <=GetMetadata()
      • IReferencedMetadataInfo
    • IHttpModuleContextContainer  <==GetModuleContextContainer()
      • IHttpStoredContext <==GetModuleContext()
        • IWebSocketContext
        • IHttpConnectionStoredContext
      • IDispensedHttpModuleContextContainer
    • IHttpSite  <==GetSite()
    • IHttpUser  <==GetUser()
    • IHttpTraceContext  <==GetTraceContext()
    • IHttpUrlInfo  <==GetUrlInfo()
    • IHttpResponse  <==GetRespons()
      • IHttpCachePolicy  <==GetCachePolicy()
        • IHttpCachePolicy2
      • IHttpResponse2
    • IHttpRequest <==GetRequest()
      • IHttpRequest2
        • IHttpRequest3
    • IScriptMapInfo <==GetScriptMap()
    • IHttpContext2
      • IHttpContext3
        • INamedContextContainer <==GetNamedContextContainer()
  • IHttpModuleRegistrationInfo
    • IHttpModuleFactory==> SetRequestNotifications()
      • IModuleAllocator <==GetHttpModule()
  • IHttpServer <==RegisterModule
    • IHttpServer2
    • IHttpPerfCounterInfo  <==GetPerfCounterInfo()   (IHttpSite::GetPerfCounterInfo() has the function)

IIS Core system

While summarizing the whole IIS native API, there are another confusing thing regarding the return value of the event handler.
At first, I imagined there should be only two such as "Continue" and "Finish", one for succes and the other for failure. But I realized that there was one more return value such as "RQ_NOTIFICATION_PENDING".
MSDN explains that it is used for asynchronous task handling but it was not that helpful because I didn't know how IIS and module should work together. 
So before understanding that, I had to make some curiosity about how IIS actually works and finally I managed to make some big ficture of IIS internal system and even made a very simple program which explains the relationship between the important Interface classes and our module classes which we should develop. The below attached code is compliable code in any C++ compiler. I just wanted to create my own simplified version of important IIS native API interfaces and classes. The purpose of the small program was to simulate how IIS handles the request and call IIS modules in its module pipeline, supposing there is only one module. Actual life cycle of request would be like as the following steps though:

  • IIS reads the applicationhost.config and prepare a list data structure of module objects in order to make all of the modules work for the request; Each module object implement event handler functions.
  • Now, IIS is ready and OS kernel system such as HTTP receive a request from wire and passes the request object to IIS
  • And then IIS creates a HttpContext object and copy the pointer of the request object to the HttpContext object, which will be used by modules
  • IIS creates a IISEventHandler object and the pointer of the HttpContext object is also copied to it
  • IIS call the event handler function of each module with the parameter of the IISEventHandler object
  • Each module participate in manipulating the request object and response body in its event handler functions
  • Once all modules finish the event handler functions, IIS give the response body to OS kernel system such as HTTP service

Summary

Today, I tried to review what I learned while trying the sample example codes of http://msdn.microsoft.com/en-us/library/aa347664(v=vs.90).aspx (IIS Native-Code Extensibility API Reference).
In the next time, I will write my own module to experiment more and share about that.

Source code of IIS and module simulation

#include "stdafx.h"
#include <iostream>
using namespace std;

class IHttpContext
{
public:
 virtual void SetHttpRequest(int newValue)=0;
};

class IHttpEventProvider
{
public:
 virtual IHttpContext* GetHttpContext()=0;
};

class HttpContext : IHttpEventProvider, IHttpContext
{
private:
 int* _pHttpRequest;

public:
 HttpContext(int* pHttpRequest) : _pHttpRequest(pHttpRequest)
 {
 }

 void SetHttpRequest(int newValue)
 {
  *_pHttpRequest=newValue;
 }

 IHttpContext* GetHttpContext()
 {
  return this;
 }
};

class HttpEventProvider: IHttpEventProvider
{
private:
 IHttpContext* _pHttpContext;

public:
 HttpEventProvider(IHttpContext* pHttpContext) : _pHttpContext(pHttpContext)
 {
 }

 virtual IHttpContext* GetHttpContext()
 {
  return _pHttpContext;
 }
};

class IModule
{
public:
 virtual void OnBeginRequest(IHttpEventProvider* provider)=0;
};

class Module : IModule
{
public:
 void OnBeginRequest(IHttpEventProvider* pHttpEventProvider)
 {
  IHttpContext* pHttpContext=pHttpEventProvider->GetHttpContext();
  pHttpContext->SetHttpRequest(3);
 }
};

int _tmain(int argc, _TCHAR* argv[])
{
  // Step 1.
 // let's suppose httpRequest object is integer value and was created in the beginning.
 // In actual world, the request object is created by http sys service for every request
 int httpRequest=0;
 cout << "Original Request: " << httpRequest << endl;

 // Step 2.
 // Now, IIS create the module object here to process the request.
 //In the actual world, it was done by IIS's calling the IHttpModuleFactory::GetModule() method in each module .dll file.
 Module* pModule=new Module();

 // Step3.
 // After creating module object, IIS create HttpContext object with copying the httpRequest object inside it.
 HttpContext* pHttpContext=new HttpContext(&httpRequest);

 // Step4
 // And then, IIS creates httpEventProvider object, which will be used by the parameter object of the event handler function which is implemented in each module .dll file
 // As you can see here, the HttpContext object information copied to httpEventProvider object so that event handler can access the httpContext object
 HttpEventProvider httpEventProvider((IHttpContext*) pHttpContext);

 // Step5
 // IIS creates state machine which invokes each deterministic request level events handler which is implemented in each module .dll file.
 // In actual world, there are global level event and non-deterministic request level events and they are fired outside of this state machine.
 IModule* pIModule;
 pIModule=(IModule*) pModule;
 pIModule->OnBeginRequest((IHttpEventProvider *) pHttpContext);

 // Step6
 // Now the state machine is finished and then response object is passed to the http sys service and it transfer it to the client which started the httpRequest.
 cout << "Modified request by module: " << httpRequest << endl;

 // Step7
 // After all of the request is finished, the httpContext and module object is deleted to clean up
 delete pModule;
 delete pHttpContext;

 // In actual world, the event handler function can be implemented to support to handle asyncronous tasks but it wasn't explained here. I will explain it later.
 return 0;
}

IIS Powershell: Getting config section names and attributes names dynamically

$
0
0

IIS Powershell provider cmdlets require the config section path for the -filter parameter and the attribute names while getting/setting attribute value.

But it is not easy to memorize the full configuration path or attribute names for each config section.

So, I have created a utility method and a useful variable, such as $iis, and I put the full source code below so that you can customize if you want.

How to use this tool.

  1. Start powershell.exe
  2. Copy the below code and paste onto the powershell window to register the one utility function, Get-WebSchema, and to create a powershell variable, $iis with using the utility function
  3. Try to run the Example Scenario 6~9 and you will see how you can use this tool with the IIS Powershell cmdlets. (NOTE: you will know you can use the auto-tab funcationality while using the $iis variable, which is what I told about getting config section names and attribute names dynamically as the following example:

    # Ex.) without using $iis variable; users should know the full config path and attribute name
    >> PS C:Windowssystem32> Get-WebConfigurationProperty -filter /system.webServer/security/authentication/basicAuthentication -name enabled

    # Ex.) using $iis variable; users can use the auto-tab to get the config section name string using $iis
    >> Get-WebConfigurationProperty -filter $iis.basicAuthentication -name $iis.basicAuthentication._enabled
####  Copy and paste from here!!!
#
#     -------------------------- EXAMPLE 1 --------------------------
#     C:\> Get-WebSchema -list
#     This command retrieves the list of schema files that are available.
#
#     -------------------------- EXAMPLE 2 --------------------------
#     C:\> Get-WebSchema -list -fileName "$env:windir\system32\inetsrv\config\schema\IIS_schema.xml"
#     This command retrieves the list of sections that are available for IIS_Schema.xml file.
#
#     -------------------------- EXAMPLE 3 --------------------------
#     C:\> Get-WebSchema -list -fileName "$env:windir\system32\inetsrv\config\schema\IIS_schema.xml" -sectionName system.webServer/asp
#     This command retrieves an xml node object for the asp section in Iis_Schema.xml file.
#
#     -------------------------- EXAMPLE 4 --------------------------
#     C:\> Get-WebSchema -fileName "$env:windir\system32\inetsrv\config\schema\IIS_schema.xml" -sectionName system.webServer/asp
#     This command list all config information (Ie. attribute/method/element/collection) of the asp section
#
#     -------------------------- EXAMPLE 5 --------------------------
#     C:\> Get-WebSchema -fileName "$env:windir\system32\inetsrv\config\schema\IIS_schema.xml"
#     This command list all config information (Ie. attribute/method/element/collection) of the IIS_Schema file
#
#     -------------------------- EXAMPLE 6 --------------------------
#     C:\> $iis
#     This command will dump all available config sections
#
#     -------------------------- EXAMPLE 7 --------------------------
#     C:\> $iis.site
#     This command will return string value of the full config path such as system.applicationHost/sites/site
#
#     -------------------------- EXAMPLE 8 --------------------------
#     C:\> $iis.appSettings._file
#     This command will return string value of the attribute name, such as "file", of the appSettings config section.
#     (NOTE: for quick find attribute name, I put "_" string at the beginning of attribute name.
#     For the example, $iis.appSettings._<TAB> will show $iis.appSettings._file.

function global:Get-WebSchema()
{
    param(
        [string]$fileName=$null,
        [string]$sectionName=$null,
        [object]$nodeObject=$null,
        [switch]$list,
        [switch]$verbose
    )

    if ($list -and $sectionName -and -not $fileName)
    {
        throw $(Get-PSResourceString -BaseName 'ParameterBinderStrings' -ResourceId 'AmbiguousParameterSet')
    }

    if ($list -and $recurse)
    {
        throw $(Get-PSResourceString -BaseName 'ParameterBinderStrings' -ResourceId 'AmbiguousParameterSet')
    }

    if ($sectionName -and -not $fileName)
    {
        throw $(Get-PSResourceString -BaseName 'ParameterBinderStrings' -ResourceId 'AmbiguousParameterSet')
    }

    if ($list)
    {
        if ($sectionName)
        {
            [xml]$xml = Get-Content $filename
            $rootNode = $xml.get_documentElement()
            $rootNode.sectionSchema | ForEach-Object {
                $nodeObject = $_
                if ($nodeObject.name.tolower() -eq $sectionName.tolower())
                {
                    $nodeObject
                }
            }
        }
        else
        {
            if ($fileName)
            {
                [xml]$xml = Get-Content $filename
                $rootNode = $xml.get_documentElement()
                $rootNode.sectionSchema | ForEach-Object {
                    $sectionName = $_.name
                    $sectionName
                }
            }
            else
            {
                Get-ChildItem "$env:windir\system32\inetsrv\config\schema" -filter *.xml | ForEach-Object {
                    $filePath = $_.fullname
                    $filePath
                }
            }
        }
    }
    else
    {
        if (-not $fileName -and -not $nodeObject) {
            throw $($(Get-PSResourceString -BaseName 'ParameterBinderStrings' -ResourceId 'ParameterArgumentValidationErrorNullNotAllowed') -f $null,'fileName')
        }

        if (-not $nodeObject)
        {
            [xml]$xml = Get-Content $filename
            $rootNode = $xml.get_documentElement()
            $rootNode.sectionSchema | ForEach-Object {
                $nodeObject = $_
                if ((-not $sectionName) -or ($nodeObject.name.tolower() -eq $sectionName.tolower()))
                {
                    Get-WebSchema -nodeObject $_ -filename $fileName -sectionName $nodeObject.name -verbose:$verbose
                }
            }
        }
        else
        {
            ("element", "collection", "attribute", "method") | ForEach-Object {
                $type = $_.tostring()
                if ($nodeObject.$type -ne $null)
                {
                    $nodeObject.$type | ForEach-Object {
                         $leafObject = $_
                         $output = new-object psobject
                         if ($type -eq "collection")
                         {
                             $name = $leafObject.addElement
                             if ($verbose)
                             {
                                 $name = "[name]"
                             }
                         }
                         else
                         {
                             $name = $leafObject.name
                         }

                         $ItemXPath = $null
                         if ($verbose)
                         {
                             $ItemXPath = ($sectionName+"//"+$name)
                         }
                         else
                         {
                             $ItemXPath = ($sectionName+"/"+$name)
                         }
                         add-member -in $output noteproperty ItemXPath $ItemXPath
                         add-member -in $output noteproperty Name $name
                         add-member -in $output noteproperty XmlObject $leafObject
                         add-member -in $output noteproperty Type $leafObject.toString()
                         add-member -in $output noteproperty ParentXPath $sectionName
                         $output

                         if ($type -eq "element" -or $type -eq "collection")
                         {
                             Get-WebSchema -nodeObject $_ -filename $fileName -sectionName $ItemXPath -verbose:$verbose
                         }
                    }
                }
            }
        }
    }
}

$global:iis = new-object psobject
(dir "$env:windir\system32\inetsrv\config\schema\*.xml") | sort -Descending | select FullName,Name | foreach {
  $file = $_.Name
  $filepath = $_.FullName

  $saved_section = $null
  $sectionName = $null
  $sectionValue = $null

  Get-WebSchema -fileName $filePath | where {$_.Type -eq "attribute"} | foreach {
    $sectionPath = $_.ParentXPath
    $attribute = $_.Name

    ##
    ## when a new section is found
    ##
    if ($saved_section -ne $sectionPath) {

      if ($sectionName -ne $null)
      {
        ##
        ## Now that the $sectionvalue is made for a specific config section,
        ## let's add the unique $sectionName noteproperty with $sectionName value onto $iis object
        ##
        add-member -in $iis noteproperty $sectionName $sectionValue
      }

      ##
      ## Let's create a new $sectionValue with assigning a new sectionPath value
      ##
      $sectionValue = $sectionPath

      ##
      ## Let's get an unique $sectionName which was not used before
      ##
      $tokens = $sectionPath.split("/")
      $sectionName = $tokens[$tokens.length-1]

      if ($tokens.length -gt 1 -and $tokens[$tokens.length-1] -eq "add")
      {
        $sectionName = $tokens[$tokens.length-2] + "_" + $tokens[$tokens.length-1]
      }

      ##
      ## if existing one has the same section configPath, copy it to the $sectionValue and then remove existing one in order to append
      ##
      if ($iis.$sectionName -ne $null -and $iis.$sectionName -eq $sectionPath)
      {
        $sectionValue = $iis.$sectionName
        $iis = $iis | select * -exclude $sectionName
      }

      if ($iis.$sectionName -ne $null)
      {
        $i = 2;
        do
        {
          $temp = $sectionName + $i
          $i = $i + 1
        }
        while ($iis.$temp -ne $null)
        $sectionName = $temp
      }

      # reset $saved_section variable with the new section path
      $saved_section = $sectionPath
    }

    ##
    ## Let's add all of the attributes as a child noteproperty onto the $sectionValue string object
    ##
    $sectionValue = $sectionValue | add-member -membertype noteproperty -name ("_"+$attribute) -value $attribute -passthru
  }

  if ($sectionName -ne $null)
  {
    ##
    ## Let's process the last $sectionValue after loop statement
    ##
    add-member -in $iis noteproperty $sectionName $sectionValue
  }
}

Developing IIS Native module 2 (Replacing response body with WriteEntityChunkByReference)

$
0
0

Summary:

In the last blog, I tried to explain the big picture for IIS native API. So, next thing is to make a real native module. Because IIS native api is huge, I will introduce one by one with some interesting topics and explain why I was interested in for the specific topic.

In this blog, I decided to make a small program with which I can replace the response body with a specific data so that I can learn how to use the IIS native API for manipulating the response data. As usual, I had to solve some issues and hope to share what I learned while solving the problem.

What I learned:

If you look at the attached code below, you will notice the following two lines, which was my first issue to solve.

//char szBuffer[BUFFERLENGTH];
//char szBuffer2[BUFFERLENGTH];  

Because I did not know what memory should be used to set the FromMemory.pBuffer pointer, I started with a stack memory which is used by local variable and I realize it does not work. I got bunch of 0 values or some garbage data.
And then I realize that IIS API requires the memory should be kept in the life cycle of the request and that's why the stack memory did not work. Also, I realize httpContext has AllocateRequestMemory() method and we can allocate a certain size of memory with using it and the memory is kept during the life cycle of the request. So, I got the answer how to fix the first issue.

And then I wanted to display some non-English string and I realize the non-English string, for example Unicode string, should be encoded in UTF8 so that IE can display the data correctly.

I used WriteEntityChunkByReference() API function to set response body with my own data because we can directly assign my data using the API.

One thing interesting regarding the function is we can set -1 to append the data to the existing response body data.

I used OnGlobalPreBeginRequest event handler here. Please refer to MSDN what the event handler means.  

I also added the line of "pHttpResponse->Clear();" but it does not meaningful in the OnGlobalPreBeginRequest event handler because the response body is actually already empty because the response body is not made yet in that stage.

 

#include "stdafx.h"
#define _WINSOCKAPI_
#include <httpserv.h>

class MyGlobalModule : public CGlobalModule
{
public:

    GLOBAL_NOTIFICATION_STATUS
    OnGlobalPreBeginRequest(IN IPreBeginRequestProvider * pProvider)
    {
        HRESULT hr = S_OK;
        IHttpContext* pHttpContext = pProvider->GetHttpContext();
        IHttpResponse * pHttpResponse = pHttpContext->GetResponse();

        if (pHttpResponse != NULL)
        {
            HTTP_DATA_CHUNK dataChunk1;
            HTTP_DATA_CHUNK dataChunk2;

            pHttpResponse->Clear();

            int BUFFERLENGTH = 256;

            //char szBuffer[BUFFERLENGTH];
            //char szBuffer2[BUFFERLENGTH];

            char* szBuffer = (char *) pHttpContext->AllocateRequestMemory(BUFFERLENGTH);
            char* szBuffer2 = (char *) pHttpContext->AllocateRequestMemory(BUFFERLENGTH);

            dataChunk1.DataChunkType = HttpDataChunkFromMemory;
            strcpy_s(szBuffer, 255, "Hello world!!!\r\n");

            dataChunk1.FromMemory.pBuffer = (PVOID) szBuffer;
            dataChunk1.FromMemory.BufferLength = (ULONG) strlen(szBuffer);
            hr = pHttpResponse->WriteEntityChunkByReference( &dataChunk1, -1);

            if (FAILED(hr))
            {
                pProvider->SetErrorStatus( hr );
                return GL_NOTIFICATION_HANDLED;
            }

            dataChunk2.DataChunkType = HttpDataChunkFromMemory;
            wchar_t wstrTest1[] = L"안녕하세요";
            int encodedStrLen = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) wstrTest1, -1, szBuffer2, BUFFERLENGTH, NULL, NULL);

            dataChunk2.FromMemory.pBuffer = (PVOID) szBuffer2;
            dataChunk2.FromMemory.BufferLength = encodedStrLen;
            hr = pHttpResponse->WriteEntityChunkByReference( &dataChunk2, -1);

            if (FAILED(hr))
            {
                pProvider->SetErrorStatus( hr );
                return GL_NOTIFICATION_HANDLED;
            }
            return GL_NOTIFICATION_HANDLED;
        }

        return GL_NOTIFICATION_CONTINUE;
    }

    VOID Terminate()
    {
        delete this;
    }

    MyGlobalModule()
    {
    }

    ~MyGlobalModule()
    {
    }
};

HRESULT
__stdcall
RegisterModule(
    DWORD dwServerVersion,
    IHttpModuleRegistrationInfo * pModuleInfo,
    IHttpServer * pGlobalInfo
)
{
    UNREFERENCED_PARAMETER( dwServerVersion );
    UNREFERENCED_PARAMETER( pGlobalInfo );

    MyGlobalModule * pGlobalModule = new MyGlobalModule;

    if (NULL == pGlobalModule)
    {
        return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
    }

    return pModuleInfo->SetGlobalNotifications(
        pGlobalModule, GL_PRE_BEGIN_REQUEST );
}

How to test the source code:

1. Logon as local administrator's account onto a machine where IIS is installed

2. Create a Visual C++ project of "Class Library" to make a DLL.

3. Copy and paste the above code

4. Right-mouse click the "Source Files" folder and click "Add" context menu and then select "New Item..."

5. Choose "Module-Definition File (.def)" and create a new .def file and paste the following 3 lines (NOTE: the "mod_HelloWorld" was used here because my project is to create the mod_HelloWorld.dll file; you should use the name of the dll file which is created by your project instead of the "mod_HelloWorld"):

LIBRARY "mod_HelloWorld"
EXPORTS
RegisterModule

6. Create a local directory such as c:privates

7. Compile the project to make the dll file, mod_HelloWorld.dll for example, and copy the dll file onto the newly created local directory

8. Open %windir%system32inetsrvconfigapplicationhost.config file and add two lines of <add>, one in the globalModules section and the other in the modules section, as the following:
        ...
            <add name="mod_HelloWorld" image="C:privatesmod_HelloWorld.dll" />
        </globalModules>

        ... 

            <add name="mod_HelloWorld" />
        </modules>
9. Launch IE and send http://localhost request and now you will see the response body is replaced with "Hello world!!! 안녕하세요". (FYI, if the result is displayed with broken characters, the current encoding is not UTF8, which can be fixed by right-mouse-clicking the IE's main page, selecting "Encoding" context menu and choosing the "Unicode (UTF-8)" encoding.

Conclusion:

Now, I hope you feel confident about how to use the WriteEntityChunkByReference API for manipulating the response body and how to handle non English string to make response body with using this simple module.

If you are not clear yet, please try to read the code carefully and try to update the code as you want. I realize the best way to learn programing is to do it by myself without other's help. IIS native API, however, is too huge to catch them easily but you will feel it is actually not that huge eventually. 

I will try to introduce more interesting topic in the next time. 

Examples of IIS Powershell cmdlets

$
0
0

Summary:

This document explains how to specify the values of parameter values and how the configuration file is updated by IIS Powershell generic cmdlets such as Get-WebConfiguration and Get-WebConfigurationProperty so that users can use them effectively.

I'd like to inform that the configuration editor of IIS8 has an useful feature to generate IIS Powershell cmdlets. You can use that feature if you want to get the example usage quickly. 

  

  1. Examples how to use parameter values

-PSPATH

COMMAND Examples:  -PSPATH is used to specify the target web object such as server/site/web application/virtual directory and physical directory. The following examples show that there are two equivalent type of PSPATH

 

## Using the path form which is used by MWA and you can specify MACHINE or MACHINE/WEBROOT level as well in this form; The "MACHINE/WEBROOT/APPHOST" is equivalent to "IIS:\", which is another form of PSPATH

$filter = "appSettings"

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

Get-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName

 

## IIS Powershell provider style PSPATh, which starts with "IIS:\"

$pspath = 'IIS:\Sites\Default Web Site\webapplication1'

Get-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName

 

## Even -pspath parameter don't need to be specified if the current directory location is changed to that place

Cd  'IIS:\Sites\Default Web Site\webapplication1'

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

TIP

  1. For server level configurations such as config section which starts with system.applicationhost, we can skip to specify the pspath parameter also

-Filter

COMMAND Examples:  -Filter can be xpath form to specify a specific or multiple  items of IIS config object such as element/collection/attribute; It will be very useful for you to know various xpath style value to enumerate IIS configurations. 

 

## Specify a site element section with xpath style value

$filter = "//sites/site"

$propertyName = "id"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a site element section with full path value

$filter = "system.applicationHost/sites/site"

$propertyName = "id"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Enumerating site (NOTE: the following five xpath examples are equivalent  in IIS config file and shows that you can use wild card value. FYI, "." means a collection item, which can be optional for specifying collection items)

Get-WebConfiguration -filter /system.applicationHost/sites/site

Get-WebConfiguration -filter /system.applicationHost/sites/site/.

Get-WebConfiguration -filter /*/*/site

Get-WebConfiguration -filter //sites/site

Get-WebConfiguration -filter //*/sites/site

 

## Enumerating name attribute of site (NOTE: the following two xpath examples are equivalent)

Get-WebConfiguration -filter /system.applicationHost/sites/site/@name

Get-WebConfiguration -filter //sites/site/@name

Get-WebConfiguration -filter //sites/site/./@name

 

## Specify a certain site node with filtering with multiple attribute values

$filter = "/system.applicationHost/sites/site[@name='Default Web Site' and @id='1']"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain site node with a single attribute value

$filter = "/system.applicationHost/sites/site[@name='Default Web Site']"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain site node with contains() function to say that its attribute "name" should contain a specific string

$filter = "/system.applicationHost/sites/site[contains(@name,'Default')]" 

Get-WebConfigurationProperty -filter $filter -name $propertyName
 

## Specify a certain site node with last() function to say that its attribute "name"  should end with a specific string

$filter = "/system.applicationHost/sites/site[last(@name,'Site')]"

Get-WebConfigurationProperty -filter $filter -name $propertyName
 

## Specify a certain site node with starts-with() function to say that its attribute "name" should start with a specific string

$filter = "/system.applicationHost/sites/site[starts-with(@name,'Default')]"

Get-WebConfigurationProperty -filter $filter -name $propertyName
 

## Specify a certain site node with position() function to say it should be placed at first

$filter = "/system.applicationHost/sites/site[position()=1]"

Get-WebConfigurationProperty -filter $filter -name $propertyName
 

## Specify a certain site node with count() to say that its parent should have only one site node 

$filter = "//*[count(site)=1]/site"

Get-WebConfigurationProperty -filter $filter -name $propertyName
 

## Specify a certain site node with name() to say that the element name should be "site"

$filter = "//*[name()='site']"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain site node with local-name() to say that the element name should be "site"

$filter = "//*[local-name()='site']"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain site node with starts-with() function to say that the element name should start "site"  should end with a specific string

$filter = "//*[starts-with(name(),'site')]"

Get-WebConfigurationProperty -filter $filter -name $propertyName
 

## Specify a certain site node with concat() function to say that the combined string of name and id attributes should be a specific string, "Default Web Site1", which is "Default Web Site" + "1"

$filter = "/system.applicationHost/sites/site[concat(@name, @id)='Default Web Site1']"

Get-WebConfigurationProperty -filter $filter -name $propertyName
 

## Specify a certain node with substring-after() function to say that the node name should contains  a specific string such as "site"

$filter = "//*[substring-after(name(), 'site')]"

Get-WebConfigurationProperty -filter $filter -name $propertyName
 

## Specify a certain node with substring-before() function to say that the node name should contains  a specific string such as "ite"

$filter = "//*[substring-before(name(), 'ite')]"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain node with substring function to say that the node name's substring start 0th with length 2 should be a specific string such as "si"

$filter = "//*[substring(name(),0,2)='si']"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain node with string-length() function to say that the legnth of the node name should be 4

$filter = "//*[string-length(name())=4]"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain node with string-length() function to say that the legnth of the node name should be 4

$filter = "//*[string-length(name())=4]"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain site node with translate() function to say that its name attribute value should be "default web site" if "D" in the original string is replaced with "d", "W" with "w", and "S" with "s" as well

$filter ="/system.applicationHost/sites/site[translate(@name, 'DWS', 'dws')='default web site']"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain site node with compare-string-ordinal() function to say that its name attribute should be "default web site" in comparing case-in-sensitively

$filter ="/system.applicationHost/sites/site[compare-string-ordinal(@name,'default web site',true())=0]"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain site node with compare-string-ordinal() function to say that its name attribute should be "Default Web Site" in comparing case-in-sensitively

$filter ="/system.applicationHost/sites/site[compare-string-ordinal(@name,'Default Web Site',false())=0]"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Specify a certain site node with compare-string-ordinal() function to say that its name attribute should be "Default Web Site" in comparing case-in-sensitively

$filter ="/system.applicationHost/sites/site[compare-string(@name,'Default Web Site',true())=0]"

Get-WebConfigurationProperty -filter $filter -name $propertyName

 

## Using "and" and "or" for set multiple condition using contains() function

$filter='/system.webServer/handlers[(contains(@accessPolicy, "Script") and contains(@accessPolicy, "Write")) or (contains(@accessPolicy, "Execute") and contains(@accessPolicy, "Write"))]'

Get-WebConfiguration -filter $filter -recurse

 

## following xpath functions are also supported:

Normalize-space(), Boolean(), Not(), Number(), Sum(), Floor(), Ceiling(), Round() and Compare-string()

-Name

COMMAND Examples:  -Name parameter is used by Get-WebConfigurationProperty and it is used to specify not only property name but also collection item

 

## Return attribute object for a specific attribute of "name"

Get-WebConfigurationProperty -filter "/system.applicationHost/sites/site" -name name

 

## Return list of collection objects  using "." or Collection which are special attribute name to specify collection items

Get-WebConfigurationProperty -filter "/system.applicationHost/sites" -name .

Get-WebConfigurationProperty -filter "/system.applicationHost/sites" -name Collection


NOTE: Even though the actual objects returned by the above two commands are exactly the same but the output in display could look different each other.

 

## When collection is used, users can filter out with query in the form of [attributeName=value] 

Get-WebConfigurationProperty -filter "/system.applicationHost/sites" -name Collection[name="Default Web Site"]

 

TIP

  1. The above command can be replaced with using xpath filtering from -filter value as the following:

Get-WebConfigurationProperty -filter "/system.applicationHost/sites/site[@name='DefaultWeb Site']" -name .

  1. Even users can use wild character in the filtering out form, which is not allowed in xpath

Get-WebConfigurationProperty -filter "/system.applicationHost/sites" -name Collection[name="Default*"]

  1. There are special purpose of property name such as Sections and SectionGroups to manage sections

 -Recurse

COMMAND Examples: When -Recurse parameter is used with Get-WebConfiguration or Get-WebConfigurationProperty, users can query recursively not only from the current directory

get-webconfiguration '/system.webServer/handlers[(contains(@accessPolicy, "Script") and contains(@accessPolicy, "Write")) or (contains(@accessPolicy, "Execute") and contains(@accessPolicy, "Write"))]' -recurse

TIP:

  1. You might be confused if you use the -recurse parameter from child level and you got no result. For the example, if you enable  basicAuthentication on Default Web Site and run the following command, you will get empty result. This is because the authentication setting is actually configured in the server level configuration file such as applicationhost.config using location tag of "<location path="Default Web Site">".
     

Get-WebConfigurationProperty '//basicAuthentication' -name enabled   -pspath "MACHINE/WEBROOT/APPHOST/Default

Web Site"  -Recurse

 

In the same situation, if you use the following command with specifying the server level for the pspath parameter, you will get the result.

Get-WebConfigurationProperty '//basicAuthentication' -name enabled   -pspath "MACHINE/WEBROOT/APPHOST"  -Recurse

 

If the authentication setting was configured in the web.config of Default Web Site's root directory after delegating the authentication configuration to site level, both of the above two commands  will work because the actual configuration is now set in the Default Web Site level.

-Value

COMMAND Examples:  When -Value  parameter is used by IIS powershell cmdlet, it usually set with a single string value (NOTE: if the value contains space, it should be quoted with " or ')
 

## The value can be hash table object if it is used to set a collection item

add-webconfiguration '/system.applicationHost/sites/site[@name="Default Web Site"]/bindings'-value @{protocol="http";bindingInformation="*:80:"} -pspath iis:\ 

 

  1. Adding  "file" attribute

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings file="test">    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

$propertyName = "file"

$propertyValue =  "test"

 

Set-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value $propertyValue

 

  1. Removing "file" attribute

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettingsfile="test">    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings/@file"

 

clear-WebConfiguration -pspath $pspath -filter appSettings/@file

 

  1. Locking "file" attribute only

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings lockAttributes="file">    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings/@file"

$lockType = "inclusive"

 

Add-WebConfigurationLock -pspath $pspath -filter $filter -type $lockType

 

  1. Unlock "file" attribute with removing the lockAttributes attribute, which is a specialized attribute

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings lockAttributes="file">    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings/@file"

 

Remove-WebConfigurationLock -pspath $pspath -filter $filter

 

  1. Locking all attributes except "file" attribute with using lockAllAttributesExcept attribute which is a specialized attribute

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings lockAllAttributesExcept="file">    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings/@file"

$lockType = "exclusive"

 

Add-WebConfigurationLock -pspath $pspath -filter $filter -type $lockType

 

  1. Removing  the exclusive lock which is set by lockAllAttributesExcept attribute which is a specialized attribute

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings lockAllAttributesExcept="file">    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

COMMAND Examples: (NOTE: Remove-WebConfigurationLock does not support removing the exclusive lock; As a work-around, we should remove the whole section and copy the previous items)

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

$propertyName = "."

 

$items = (get-webconfigurationproperty -pspath $pspath -filter $filter -name $propertyName).collection

 

Clear-WebConfiguration  -pspath $pspath -filter $filter

 

$items | foreach { Add-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value @{key=$_.key;value=$_.value}  }

 

  1. Adding collection item

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings file="test">    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

$propertyName = "."

$propertyValue =  @{key='ee';value='ee'}

 

Add-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value $propertyValue

 

  1. Modifying property value of collection item

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings file="test">    

      <add key="foo2" value="bar" />

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings/add[@key='foo']"

$propertyName = "key"

$propertyValue =  "foo2"

 

Set-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value $propertyValue

 

  1. Reverting to parent with removing whole config section

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

      <clear/>       

        <add key="foo" value="bar"/>

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

</configuration>

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

 

Clear-WebConfiguration  -pspath $pspath -filter $filter

 

  1. Removing <clear />

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

      <clear/>       

        <add key="foo" value="bar"/>

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

        <add key="foo" value="bar"/>

    </appSettings>

</configuration>

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

$propertyName = "."

 

$items = (get-webconfigurationproperty -pspath $pspath -filter $filter -name $propertyName).collection

 

Clear-WebConfiguration  -pspath $pspath -filter $filter

 

$items | foreach { Add-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value @{key=$_.key;value=$_.value}  }

 

  1. Removing all collection items of the current level only

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <remove key="foo_parent" />

      <add key="foo" value="bar"/>

      <add key="foo2" value="bar2"/>

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

      <remove key="foo_parent" />

    </appSettings>

</configuration>

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

$propertyName = "."

 

$items = (get-webconfigurationproperty -pspath $pspath -filter $filter -name $propertyName).collection  | where {$_.getmetadata("collectionItemFileConfigPath") -eq $pspath }

 

$items | foreach { Remove-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -AtElement @{key=$_.key}  }

 

  1. Remove a specific <remove> item of key value "foo_parent"

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

      <remove key="foo_parent" />

      <remove key="foo_parent2" />

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

      <remove key="foo_parent2" />

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$pspath_parent = 'MACHINE/WEBROOT/APPHOST/Default Web Site'

$filter = "appSettings"

$propertyName = "."

$KeyValue= "foo_parent"

 

$parentItems = (get-webconfigurationproperty -pspath $pspath_parent -filter $filter -name $propertyName).collection

$inheritedItems = (get-webconfigurationproperty -pspath $pspath -filter $filter -name $propertyName).collection  | where {$_.getmetadata("collectionItemFileConfigPath") -ne $pspath }

$localitems = (get-webconfigurationproperty -pspath $pspath -filter $filter -name $propertyName).collection  | where {$_.getmetadata("collectionItemFileConfigPath") -eq $pspath }

 

$removedItems = @{}

$parentItems | foreach {

     $item = $_

     $itemFound = $inheritedItems | where { ($_.key -eq $item.key) -and  ($_.value -eq $item.value) }

     if (($itemFound -eq $null) -and ( $item.key -ne $KeyValue))

     {

       $removedItems.add($item.key, $item.value)

     }

}

 

Clear-WebConfiguration  -pspath $pspath -filter $filter

 

$localitems | foreach { Add-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value @{key=$_.key;value=$_.value}  }

 

$removedItems.Keys | foreach { Remove-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -AtElement @{key=$_}  }

 

  1. Remove all collection items including items inherited from parents

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

     <add key="foo" value="bar"/>

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

    <clear/>        

    </appSettings>

</configuration>

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

$propertyName = "."


Rem
ove-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName

 

  1. Remove "foo_parent" collection item which is inherited from parent level)

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

     <add key="foo" value="bar"/>

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>

       <remove key="foo_parent" />

        <add key="foo" value="bar"/>

    </appSettings>

</configuration>

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

$propertyName = "."

$propertyValue =  "foo_parent"

 

Remove-WebConfigurationProperty  -pspath $pspath -filter $filter -name $propertyName -AtElement @{key=$propertyValue}

 

  1. Remove "foo" collection item for a specific file such as default.aspx which is placed at the current directory

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar"/>

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

    <location path="default.aspx">

        <appSettings>

            <remove key="foo" />

        </appSettings>

    </location>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

$propertyName = "."

$propertyValue =  "foo"

$locationPath =  "default.aspx"

 

Remove-WebConfigurationProperty  -pspath $pspath -filter $filter -name $propertyName -AtElement @{key=$propertyValue} -location $locationPath

 

  1. Reverting to parent for the default.aspx location

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

    <location path="default.aspx">

        <appSettings>

            <remove key="foo" />

        </appSettings>

    </location>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

    <location path="default.aspx">

    </location>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings"

$propertyName = "."

$propertyValue =  "foo"

$locationPath =  "default.aspx"

 

clear-webconfiguration  -pspath $pspath -filter $filter -name $propertyName -AtElement @{key=$propertyValue} -location $locationPath

 

  1. Locking collection item

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings file="test">    

      <add key="foo" value="bar"lockItem="true"/>

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings/add[@key='foo']"

$lockType = "general"

 

Add-WebConfigurationLock -pspath $pspath -filter "appSettings/add[@key='foo']" -type $lockType

 

  1. Unlocking collection item

FROM:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar"lockItem="true"/>

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings file="test">    

      <add key="foo" value="bar"/>

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST/Default Web Site/webapplication1'

$filter = "appSettings/add[@key='foo']"

 

Remove-WebConfigurationLock -pspath $pspath  -filter $filter

 

  1. Set machine level with specifying framework version of v2.0, which is different to the default value -> This is only applicable for Windows 2012

FROM: for the root web.config file of .Net v2.0

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

    </appSettings>

</configuration>

 

TO:

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

    <appSettings>    

      <add key="foo" value="bar" />

    </appSettings>

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT'

$filter = "appSettings"

$propertyName = "file"

$propertyValue =  "test"

$clrVersion = "v2.0"

 

Set-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value $propertyValue -clr $clrVersion

 

  1. Locking item from section level

FROM: for the applicationhost.config file

...

</configuration>

 

TO:

...

    <appSettings lockItem="true" />

</configuration>

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST'

$filter = "appSettings"

$type="general"

 

Add-WebConfigurationLock-pspath $pspath -filter $filter

 

  1. Remove section level lock

FROM: for the applicationhost.config file

...

    <appSettings lockItem="true" />

</configuration>

 

TO:

    <appSettings/>

</configuration>

...

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST'

$filter = "appSettings"

 

Remove-WebConfigurationLock-pspath $pspath -filter $filter

 

  1. Add a new section group

FROM: for the applicationhost.config file

...

    </configSections>

...

 

TO:

        <sectionGroup name="MySectionGroup" />

    </configSections>

...

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST'

$filter = "/"

$propertyName = "sectionGroups"

$propertyValue =  "MySectionGroup"

 

Add-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value $propertyValue

 

  1. Delete a section group

FROM: for the applicationhost.config file

...

        <section name="MySection" />

    </configSections>

...

 

TO:

    </configSections>

...

 

COMMAND Examples:

 

## FYI, This is to show how to get the section object at root level

get-WebConfigurationProperty -pspath iis:\ -filter / -name sectionGroups["MySectionGroup"]

 

## Delete the section group

Remove-WebConfigurationProperty -pspath iis:\ -filter "/" -name sectionGroups["MySectionGroup"]

 

  1. Add a new section

FROM: for the applicationhost.config file

...

    </configSections>

...

 

TO:

        <section name="MySection" />

    </configSections>

...

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST'

$filter = "/"

$propertyName = "sections"

$propertyValue =  "MySection"

 

Add-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value $propertyValue

 

  1. Delete a section

FROM: for the applicationhost.config file

...

        <section name="MySection" />

    </configSections>

...

 

TO:

    </configSections>

...

 

COMMAND Examples:

 

## FYI, This is to show how to get the section object at root level

get-WebConfigurationProperty -pspath iis:\ -filter / -name sections["MySection"]

 

## Delete the section

Remove-WebConfigurationProperty -pspath iis:\ -filter "/" -name sections["MySection"]

 

  1. Add a new section under a specific section group

FROM: for the applicationhost.config file

...

        <sectionGroup name="MySectionGroup" />

    </configSections>

...

 

TO:

        <sectionGroup name="MySectionGroup">

             <section name="MyChildSection" />

        </sectionGroup>           

    </configSections>

...

 

COMMAND Examples:

 

$pspath = 'MACHINE/WEBROOT/APPHOST'

$filter = "/MySectionGroup"

$propertyName = "sections"

$propertyValue =  "MyChildSection"

 

Add-WebConfigurationProperty -pspath $pspath -filter $filter -name $propertyName -value $propertyValue

 

  1. Delete a section under a specific section group

FROM: for the applicationhost.config file

...

        <sectionGroup name="MySectionGroup">

             <section name="MyChildSection" />

        </sectionGroup>           

    </configSections>

...

 

TO:

        <sectionGroup name="MySectionGroup" />

    </configSections>

...

 

COMMAND Examples:

 

## FYI, This is to show how to get the section object under the specific section group

get-WebConfigurationProperty -pspath iis:\ -filter /MySectionGroup -name sections["MyChildSection"]

 

## Delete the section

Remove-WebConfigurationProperty -pspath iis:\ -filter "/MySectionGroup" -name sections["MyChildSection"]

 

  1. Configure "Deny" for OverrideModeDefault attribute of a specific section

FROM: for the applicationhost.config file

...

        <sectionGroup name="system.webServer">

            <section name="asp" overrideModeDefault="Deny" />

...

 

TO:

        <sectionGroup name="system.webServer">

            <section name="asp" overrideModeDefault="Allow" />

...

 

COMMAND Examples:

 

Set-WebConfigurationProperty -filter /system.webServer -name 'sections["asp"].OverrideModeDefault' -value Allow -pspath iis:\

 

 

Running Tomcat with IIS on Nano Server

$
0
0
  • Introduction
  • Setup
    • Step 1: prepare Nano server with IIS role and httpPlatformHandler
    • Step 2: install Tomcat on Nano Server
  • Configure settings
    • Step 3: configure server.xml of Tomcat
    • Step 4: configure httpPlatformHandler for Tomcat
    • Step 5: configure Default Web Site
  • Run
  • Troubleshoot

 

Introduction

 

This article shows how to set-up Tomcat and httpPlatformHandler with IIS of Nano server.

 

Setup

 

Step 1: prepare Nano server with IIS role and httpPlatformHandler

 

First you need to install IIS on Nano and then install httpPlatformHandler on your Nano server.

Installing IIS on Nano is already covered in the ariticle below, so I’ll skip those steps here for brevity.

Please notice that the article explains both "Installing IIS" and "Installing the ASP.NET Core Module (ANCM)".
You can skip installing the ASP.NET Core Module (ANCM) because ANCM is not required for running Tomcat on Nano server.

Once you installed IIS on your Nano server, now you are ready to install HttpPlatformHandler on your Nano server.

In order to install HttpPlatformHandler on your Nano server, you have to install it on your regular 64 bit(amd64) Windows machine first in order to get two files, one httpPlatoformHandler.dll and the other httpplatform_schema.xml, copy them to Nano server manually and configure required IIS configurations manually as well.

Here is how to do that step by step.

On a regula 64 bit Windows machine, go to this download page which is for HttpPlatformHandler and download X64 version msi file (httpPlatformHandler_amd64.msi) and execute it to install HttpPlatformHandler on the machine. After HttpPlatform is installed, locate the following two files and copy them to your Nano server onto the same directory.

%windir%\System32\inetsrv\HttpPlatformHandler.dll
%windir%\System32\inetsrv\config\schema\httpplatform_schema.xml

FYI, on purpose, I did not mention about %windir%\Syswow64\inetsrv\HttpPlatformHandler.dll because Nano server does not support 32 bit IIS module and we don't need to copy the 32 bit dll file on Syswow64 directory.

FYI, in case you don't know how to copy any file to your Nano server, I'd like to inform that you can use Copy-Item powershell cmdlet with -ToSession paramerter.
NOTE: in order to use Copy-Item cmdlet for that purpose, you need to configure TrustedHosts for powershell remoting as you did for making the remote powershell tab to your Nano server. 

Here is the example powershell script to copy the two files to a remote Nano server. Modify the ip address of Nano Server with the real one which is used by your Nano server and run it and you will be able to copy the two files to the rigth destination. 

$ip = "<IP address of Nano Server>" # For example, $ip = "10.127.67.20"
$user = "$ip\Administrator"  # supposing you know the password of administrator account on Nano server
$s = New-PSSession -ComputerName $ip -Credential $user
Copy-Item -ToSession $s -Path "$env:windir\System32\inetsrv\HttpPlatformHandler.dll" -Destination C:\windows\system32\inetsrv\
Copy-Item -ToSession $s -Path "$env:windir\System32\inetsrv\config\schema\httpplatform_schema.xml" -Destination C:\windows\system32\inetsrv\config\schema\

After copying the two files to your Nano server, open a remote powershell tab to your Nano server and run the following powershell cmdles to complete installing httpPlatformHandler on your Nano server: 

Import-Module IISAdministration 

Reset-IISServerManager -confirm:$false
$sm = Get-IISServerManager
$appHostconfig = $sm.GetApplicationHostConfiguration()
$section = $appHostconfig.GetSection("system.webServer/handlers")
$section.OverrideMode="Allow"
$sm.CommitChanges()

Reset-IISServerManager -confirm:$false
$sm = Get-IISServerManager
$appHostconfig = $sm.GetApplicationHostConfiguration()
$sectionHttpPlatform = $appHostConfig.RootSectionGroup.SectionGroups["system.webServer"].Sections.Add("httpPlatform")
$sectionHttpPlatform.OverrideModeDefault = "Allow"
$sm.CommitChanges()

Reset-IISServerManager -confirm:$false
$globalModules = Get-IISConfigSection "system.webServer/globalModules" | Get-IISConfigCollection
New-IISConfigCollectionElement $globalModules -ConfigAttribute @{"name"="httpPlatformHandler";"image"="%windir%\system32\inetsrv\httpPlatformHandler.dll"}
 
Reset-IISServerManager -confirm:$false
$modules = Get-IISConfigSection "system.webServer/modules" | Get-IISConfigCollection
New-IISConfigCollectionElement $modules -ConfigAttribute @{"name"="httpPlatformHandler"}

FYI, after running the powershell cmdelts, the c:\windows\system32\inetsrv\config\applicationhost.config in your Nano machine will be updated like this.

...

        <section name="httpPlatform" overrideModeDefault="Allow" />

    </sectionGroup>

</configSections>

...


    <add name="httpPlatformHandler" image="%windir%\system32\inetsrv\httpPlatformHandler.dll" />

</globalModules>

...


<add name="httpPlatformHandler" />

</modules>

...

Step 2: install Tomcat on Nano Server

 

In this step you will set-up JDK and Tomcat on your Nano server.

In order to install JDK to your Nano server, you have to install it on your regular Windows machine. You need a 64 bit OS because you will be using a 64bit JDK.

On a regular 64bit Windows machine where you can install JDK, go to this download page of JDK and download it.

 

http://www.oracle.com/technetwork/java/javase/downloads/index.html

 

You should download the latest build of Java SE Development Kit for Windows x64 platform.

The downloaded file name will be like "jdk-8u66-windows-x64.exe" if the latest JDK's version is "8u66".

Then install the JDK on the regular Windows OS machine. After installation is done, you will see the JDK installation directory has been created under "C:\Program Files\Java\jdk1.8.0_66" or a certain place you choose.

 

Now you need to actually install the JDK onto your Nano server machine.

The installation is very simple. You just need to copy the JDK directory from your regular Windows machine to a certain directory such as c:\ of your Nano server machine.

 

If you copied the JDK directory such as "jdk1.8.0_66" onto c:\ directory of Nano server machine, the directory structure should be like this.

 

[nano1]: PS C:\jdk1.8.0_66> dir

    Directory: C:\jdk1.8.0_66


Mode               LastWriteTime         Length Name                                                                                                             

----               -------------         ------ ----                                                                                                            

d-----         12/10/2015   4:52 PM               bin   

d-----         12/10/2015   4:52 PM               db    

d-----         12/10/2015   4:52 PM               include  

d-----         12/10/2015   4:52 PM               jre  

d-----         12/10/2015   4:53 PM               lib  

-a----       11/9/2015 11:09 AM           3244 COPYRIGHT                                                    

-a----         12/10/2015   4:44 PM       5104608 javafx-src.zip 

-a----         12/10/2015   4:44 PM            40 LICENSE  

-a----         12/10/2015   4:44 PM           159 README.html                                 

-a----         12/10/2015   4:44 PM           527 release 

-a----       11/9/2015 11:09 AM       21244088 src.zip                                                                                                       

-a----         12/10/2015   4:44 PM         110114 THIRDPARTYLICENSEREADME-JAVAFX.txt  

-a----         12/10/2015   4:44 PM         177094 THIRDPARTYLICENSEREADME.txt   

                                                                      

Go to this download page of Tomcat.

http://tomcat.apache.org/download-80.cgi (supposing you're going to install Tomcat v8.0).

 

Then download the "64-bit Windows zip" file. The downloaded file name will be like "apache-tomcat-8.0.30-windows-x64.zip".

Unzip the downloaded zip file and copy its content onto c:\ of your Nano server machine.

 

If you copied Tomcat directory such as "apache-tomcat-8.0.30" onto c:\ directory of Nano server machine, the directory structure should be like this.

[nano1]: PS C:\apache-tomcat-8.0.30> dir

    Directory: C:\apache-tomcat-8.0.30

Mode               LastWriteTime         Length Name                                                                                                              

----               -------------         ------ ----                                                                                                            

d-----         12/10/2015   5:22 PM               bin 

d-----         12/11/2015   2:24 PM               conf 

d-----         12/10/2015   5:22 PM               lib  

d-----         12/11/2015   1:58 PM               logs

d-----         12/10/2015   5:22 PM               temp 

d-----         12/11/2015   1:53 PM               webapps  

d-----         12/11/2015   2:24 PM               work 

-a----       12/9/2015   6:39 PM          58068 LICENSE 

-a----       12/9/2015   6:39 PM           1489 NOTICE  

-a----       12/9/2015   6:39 PM           6913 RELEASE-NOTES   

-a----       12/9/2015   6:39 PM         16671 RUNNING.txt    

 

Configure settings

 

Step 3: configure server.xml of Tomcat

 

Now you have to change the configuration file of Tomcat server which is c:\apatche-tomcat-8.0.30\conf\server.xml of your Nano server machine supposing your Tomcat directory is c:\apatche-tomcat-8.0.30.

The server.xml uses hardcoded value such as 8005 for shutdown and 8080 for startup. That should be changed to be the following:

 

FROM:

...

<Server port="8005" shutdown="SHUTDOWN">

...

<Connector port="8080" protocol="HTTP/1.1"

 

TO:

...

<Server port="-1" shutdown="SHUTDOWN">

...

<Connector port="${port.http}" protocol="HTTP/1.1"

...

 

As you can see, you need to change 8005 with -1 and 8080 with ${port.http}.

 

The value for ${port.http} will be set by httpFlatformHandler on runtime with an available TCP port number at that time. The value of the shutdown port, -1, is not actually used because the Tomcat server process runs as a child process of the IIS worker process, and it will be shut down automatically when the IIS worker process is shut down.

 

Step 4: configure httpPlatformHandler for Tomcat

 

Create a web.config file after creating a directory such as c:\inetpub\website1 and fill the file with the following content in order to configure httpFlatformHandler for Tomcat.

NOTE: This sample web.config has hardcoded values of C:\apache-tomcat-8.0.30, c:\jdk1.8.0_66 and C:\inetpub\website1. You have to adjust those values to match your Nano server environment. While adjusting values, make sure every value is pointing valid existing directory path. 

<?xml version="1.0" encoding="UTF-8"?>

<configuration>

  <system.webServer>

    <handlers>

       <add name="httpplatformhandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" />

    </handlers>

    <httpPlatform processPath="C:\apache-tomcat-8.0.30\bin\startup.bat" arguments="" stdoutLogEnabled="true" stdoutLogFile="\\?C:\inetpub\website1\log.txt">

       <environmentVariables>

         <environmentVariable name="JRE_HOME" value="c:\jdk1.8.0_66" />

         <environmentVariable name="CATALINA_OPTS" value="-Dport.http=%HTTP_PLATFORM_PORT%" />      

         <environmentVariable name="CATALINA_HOME" value="C:\apache-tomcat-8.0.30" />

       </environmentVariables>

    </httpPlatform>

    <directoryBrowse enabled="true" />

  </system.webServer>

</configuration>

 

I'd like to inform that the line enabling directoryBrowse is optional. If you enable it, it will be useful while troubleshooting. For example, you can temporarily remove the config sections of handlers and httpPlatform to check if the website works without httpFlatform.

 

Step 5: configure Default Web Site

 

Open applicationhost.config file which is placed in c:\windows\system32\inersrv\config and edit the physicalPath of Default Web Site with the "c:\inetpub\website1" where you created web.config file.

 

Run

 

Now you are ready to start. In this section you will learn how to verify Tomcat and create a sample web application.

 

Step 6: start http://<ComputerName>

 

Restart IIS services first. You can use the commands "Stop-Service was -Force -Confirm:$false" and "Start-Service w3svc".

Now you are ready start. On any client machine from which you can connect to your Nano server machine, open a web browser such as IE and browse http://<ComputerName> (NOTE: replace <ComputerName> with the computer name of your Nano server) and you will get this result if everything is okay.

Note: the first request will take some time because it takes some time to start Tomcat.

 

Step 7: add sample webapp and run http://<ComputerName>/sample

 

You can download a sample Java web application and install it onto your Tomcat directory.

Download the sample directory from https://tomcat.apache.org/tomcat-6.0-doc/appdev/sample/ and copy onto C:\apache-tomcat-8.0.30\webapps, after which a new directory such as C:\apache-tomcat-8.0.30\webapps\sample will be created.

Now, you are ready to test the sample web application with browsing http://<ComputerName>/sample.

 

Troubleshoot

Here are common mistakes I made which caused up to an error of 500 and how I fixed those issues. Check these thing if you run into similiar issue.

  1. Make sure the httpPlatform configuration section should be added inside the sectionGroup of "system.webServer", not "system.applicationHost"
  2. Make sure overrideModeDefault of the httpPlatform configuration section is set to "Allow"
  3. Make sure that the server.xml for the Tomcat server is configured correctly
  4. Make sure web.config is configured correctly, especially for directory paths
  5. You might need to restart IIS services after making configuration changes in order to apply the change
  6. You might need to restart your web browser with clearing cached result to see the updated result after making configuration changes

You might want to know how to run the Tomcat server on your regular (non-Nano) Windows machines in order to confirm that your downloaded Tomcat server  works well before installing it onto your Nano server machine.

After installing Tomcat server on regular Windows machine, run the following commands to start Tomcatserver on regular Windows machine:

set JRE_HOME=%programfiles%\Java\jdk1.8.0_66

set CATALINA_OPTS=-Dport.http=1234

set CATALINA_HOME=C:\dev\javasites\bin\apache-tomcat-8.0.30

C:\dev\javasites\bin\apache-tomcat-8.0.30\bin\startup.bat

After running this, you will see the Tomcat server running while using TCP port 1234.

Then, browse http://localhost:1234 and verify that you got the right result.

 

Running Wordpress with IIS and WinCache on Nano Server

$
0
0
  • Introduction
  • Setup Nano server
    • Step 1: prepare Nano server with IIS role
    • Step 2: expand disk size
  • Setup PHP on Nano server
    • Step 3: install PHP on Nano server
    • Step 4: install vcuntime140.dll to %windir%\system32 on Nano Server
    • Step 5: install IIS-Cgi and configure applicationhost.config for PHP
    • Step 6: verify if php is correctly configured
  • Setup Wordpress
    • Step 7: install MySQL on Nano server
    • Step 8: register MySql database server as a Windows service
    • Step 9: create a database for Wordpress
    • Step 10: configure PHP for MySQL
    • Step 11: install Wordpress package on Nano server
    • Step 12: configure Default Web Site
  • Run
  • Enhance PHP performance with WinCach
    • Step 14: Install WinCache
    • Step 15: Verify WinCache

 

Introduction

 

This article shows how to set-up Wordpress on IIS of Nano server.

 

Setup Nano server

 

You will prepare Nano server here.

 

Step 1: prepare Nano server with IIS role

 

First you need to install IIS on Nano and then install httpPlatformHandler on your Nano server.

Installing IIS on Nano is already covered in the ariticle below, so I’ll skip those steps here for brevity.

Please notice that the article explains both "Installing IIS" and "Installing the ASP.NET Core Module (ANCM)".
You can skip installing the ASP.NET Core Module (ANCM) because ANCM is not required for running Tomcat on Nano server.

Step 2: expand disk size of Nano server

 

If you use the default disk size of the Nano server image (default hard disk is 4GB), you have to expand the disk size. Otherwise, you will fail to install MySQL because there is not enough disk space.

 

You can check the current disk size with running "Get-Disk" command from Remote powershell tab.

[nano1]: PS C:\> Get-Disk

Number Friendly Name                                                                            Serial Number                     HealthStatus           OperationalStatus     Total Size Partition

                                                                                                                                                                                          Style    

------ -------------                                                                               -------------                     ------------       -----------------     ---------- ----------

0       Virtual HD                                                                                                                   Healthy             Online                     10 GB MBR      

 

If your disk size is 4 GB, shutdown your Nano server virtual machine and open the "Settings" dialog of your Nano server Virtual machine.

Then click the "Edit" button after selecting Hard Drive.

Select the "Expand" button, and set the new size with more than 10 GB. Click the "Finish" button to apply the change, and restart yocd\cdur Nano server virtual machine.

 

Setup PHP on Nano server

 

Wordpress requires PHP. Here you will learn how to install PHP on Nano server machine.

 

Step 3: install PHP on Nano server

 

In this step, you will set-up PHP on your Nano server.

 

Go to http://windows.php.net/downloads/qa/ and download the latest 64 bit PHP such as php-7.0.1RC1-nts-Win32-VC14-x64.zip.

 

The file name php-7.0.1RC1-nts-Win32-VC14-x64.zip shows that its version is PHP 7.0.1 RC1 and it is built with Microsoft Visual C v14.

 

Unzip the downloaded zip file and copy the contents to a certain directory such as c:\php of your Nano server machine.

 

Your c:\php directory structure should be like this:

[nano1]: PS C:\php> dir

    Directory: C:\php

Mode               LastWriteTime         Length Name

----               -------------         ------ ----     

d-----         12/14/2015   1:55 PM               dev    

d-----         12/14/2015   1:55 PM               ext   

d-----        12/14/2015   1:42 PM               extras   

d-----         12/14/2015   1:55 PM               lib                                                               

d-----         12/14/2015   1:55 PM               sasl2   

-a----         12/14/2015 11:47 AM         114688 deplister.exe     

-a----         12/14/2015 11:47 AM       1360384 glib-2.dll     

-a----         12/14/2015 11:47 AM         18432 gmodule-2.dll     

-a----         12/14/2015 11:47 AM       25048064 icudt56.dll       

-a----         12/14/2015 11:47 AM       2086912 icuin56.dll       

-a----         12/14/2015 11:47 AM         52224 icuio56.dll      

…                

 

Step 4: install vcruntime140.dll to %windir%\system32 on Nano Server

 

PHP depends on the vcruntime140.dll file. If the vcruntime140.dll is not available on your Nano server, PHP cannot be executed. The vcruntime140.dll is available on any 64 bit Windows machine where the latest Visual Studio is installed. So, what you should do is to find the vcruntime140.dll file and copy the file to %windir%\system32 of your Nano server machine and confirm the file is copied correctly.

 

After you copy the vcruntime140.dll correctly to your Nano server machine, you need to confirm whether running "php.exe -?" shows the correct result on your remote powershell tab as the below screenshot. If the file is not copied correctly to the right place, it will silently fail showing an empty result when you execute "php.exe -?" because it fails to load the vcruntime140.dll file.

[nano1]: PS C:\windows\system32> dir .\vcruntime140.dll

    Directory: C:\windows\system32

Mode               LastWriteTime         Length Name                                                                                                                                       

----               -------------         ------ ----                                                                                                                  

-a----       6/25/2015 11:15 PM         88752 vcruntime140.dll

 

[nano1]: PS C:\windows\system32> cd \php

 

[nano1]: PS C:\php> .\php.exe -?

Usage: php [options] [-f] <file> [--] [args...]

    php [options] -r <code> [--] [args...]

    php [options] [-B <begin_code>] -R <code> [-E <end_code>] [--] [args...]

    php [options] [-B <begin_code>] -F <file> [-E <end_code>] [--] [args...]

    php [options] -S <addr>:<port> [-t docroot]

    php [options] -- [args...]

    php [options] -a

 

  -a               Run interactively

-c <path>|<file> Look for php.ini file in this directory

  -n               No php.ini file will be used

-d foo[=bar]     Define INI entry foo with value 'bar'

  -e               Generate extended information for debugger/profiler

-f <file>       Parse and execute <file>.

  -h               This help

  -i               PHP information

  -l               Syntax check only (lint)

Step 5: install IIS-Cgi and configure applicationhost.config for PHP

 

In this step, you will install IIS-Cgi feature and update applicationhost.config to add the fastcgi module with the php installation directory path, c:\php.

Here is how to install IIS-Cgi feature. If you did not install the feature before, run the command below in order to install IIS-Cgi feature.

DISM.EXE /enable-feature /online /featureName:IIS-CGI /all

NOTE: If you see any error while running "DISM.EXE /enable-feature /online /featureName:IIS-CGI /all", try to run the same command again after running the following cmdlets on your Nano server, which is an work-around way of a known issue. 

Import-module iisadministration
Reset-IISServerManager -confirm:$false
$sm = Get-IISServerManager
$appHostconfig = $sm.GetApplicationHostConfiguration()
$section = $appHostconfig.GetSection("system.webServer/handlers")
$section.OverrideMode="Inherit"
$sm.CommitChanges()

Now, you are ready to configure applicationhost.config for PHP.

On the Nano server machine, open %windir%\system32\inetsrv\config\applicationhost.config and configure highlighted config settings as the following (NOTE: You should adjust the directory path value with the actual value of your Nano machine's environment):

 

<defaultDocument enabled="true">

           <files>

               <add value="index.php" />

 

       <fastCgi>

           <application fullPath="C:\PHP\PHP-CGI.EXE" maxInstances="0" instanceMaxRequests="10000">

               <environmentVariables>

                   <environmentVariable name="PHP_FCGI_MAX_REQUESTS" value="10000" />

                   <environmentVariable name="PHPRC" value="C:\PHP" />

               </environmentVariables>

           </application>

       </fastCgi>

 

...

           <add name="FastCgiModule" image="%windir%\System32\inetsrv\iisfcgi.dll" />

       </globalModules>

 

...

           <add name="FastCgiModule" lockItem="true" />

       </modules>

 

...

       <handlers accessPolicy="Read, Script">

          <!-- NOTE: place the following line of PHP-iisfcgi in the first line -->

           <add name="PHP-iisfcgi" path="*.php" verb="GET,HEAD,POST" modules="FastCgiModule" scriptProcessor="C:\PHP\PHP-CGI.EXE" resourceType="Either" requireAccess="Script" />  

...

You can update the above configuration settings with running following powershell commands on remote Powershell tab:  

import-module iisadministration

Reset-IISServerManager -Confirm:$false

Get-IISConfigSection system.webServer/defaultDocument | Get-IISConfigElement -ChildElementName files | Get-IISConfigCollection | New-IISConfigCollectionElement -ConfigAttribute @{"value"="index.php"}

Get-IISConfigSection system.webServer/fastCgi | Get-IISConfigCollection | New-IISConfigCollectionElement -ConfigAttribute @{"fullPath"="C:\PHP\PHP-CGI.EXE";"maxInstances"=0;"instanceMaxRequests"=10000}

Get-IISConfigSection system.webServer/fastCgi | Get-IISConfigCollection | Get-IISConfigCollectionElement -ConfigAttribute @{"fullPath"="C:\PHP\PHP-CGI.EXE"} | Get-IISConfigElement -ChildElementName environmentVariables | Get-IISConfigCollection | New-IISConfigCollectionElement -ConfigAttribute @{"name"="PHP_FCGI_MAX_REQUESTS";"value"="10000"}

Get-IISConfigSection system.webServer/fastCgi | Get-IISConfigCollection | Get-IISConfigCollectionElement -ConfigAttribute @{"fullPath"="C:\PHP\PHP-CGI.EXE"} | Get-IISConfigElement -ChildElementName environmentVariables | Get-IISConfigCollection | New-IISConfigCollectionElement -ConfigAttribute @{"name"="PHPRC";"value"="C:\PHP"}

Get-IISConfigSection system.webServer/handlers | Get-IISConfigCollection | New-IISConfigCollectionElement -ConfigAttribute @{"name"="PHP-iisfcgi";"path"="*.php";"verb"="GET,HEAD,POST";"modules"="FastCgiModule";"scriptProcessor"="C:\PHP\PHP-CGI.EXE";"resourceType"="Either";"requireAccess"="Script"} -AddAt 0

 

Step 6: verify if php is correctly configured

 

Before going further, let's check whether php is correctly installed and configured.

 

Create phpinfo.php on the root directory of the Default Web Site such as c:\inetpub\wwwroot with the following file content:

 

<?php

phpinfo();

?>

 

Open a web browser and send a request to http://<ComputerName>/phpinfo.php (NOTE: replace <ComputerName> with your Nano server's machine name) and verify that it shows the correct result of the phpinfo.php.

  

Setup Wordpress

 

Wordpress needs a database, and here, I will demonstrate how to install MySql on the Nano server and how to initialize it. Then, I will show how to install Wordpress.

 

Step 7: install MySQL on Nano server

 

In this step, you will setup MySQL on your Nano server.

 

Go to https://www.mysql.com/ and download the latest 64 bit MySQL such as mysql-5.6.26-winx64.zip.

 

Unzip the downloaded zip file and copy the contents to a directory such as c:\MySQL of your Nano server machine.

 

Your c:\mysql directory structure should be like this:

 

[nano1]: PS C:\MySql> dir

 

   Directory: C:\MySql

 

Mode               LastWriteTime         Length Name                                                                                                                                              

----               -------------         ------ ----                                                                                                                                              

d-----         12/14/2015   5:33 PM               bin    

d-----         12/14/2015   5:34 PM               data      

d-----         12/14/2015   5:34 PM              docs          

d-----         12/14/2015   5:34 PM               include                              

d-----         12/14/2015   5:35 PM               lib                                              

d-----         12/14/2015   5:45 PM               mysql-test       

d-----          9/22/2015   3:22 PM               scripts           

                                       

 

Step 8: register MySql database server as a Windows service

 

In this step you will setup MySQL on your Nano server.

Run "mysqld.exe --install" from c:\MySql\bin directory of your Nano server and restart the machine.

 

Here is the screenshot of running the "mysqld.exe --install" command to register MySql as a Windows service and to restart the machine:

[nano1]: PS C:\> cd .\MySql\bin

[nano1]: PS C:\MySql\bin> .\mysqld.exe --install

Service successfully installed.

 

[nano1]: PS C:\MySql\bin> Restart-Computer;Exit 

 

After machine has restarted, run "get-process" and you will see the mysqld process running.

 

Here is the screenshot which shows the mysqld process running:

[nano1]: PS C:\> get-process

 

Handles   NPM(K)   PM(K)     WS(K) VM(M)   CPU(s)       Id SI ProcessName                                                                                                                          

-------   ------   -----     ----- -----   ------       -- -- -----------                                                                                                                          

             6     640       1632 ...63     0.02     288   0 csrss                                                                                                                              

             5     832       3600 ...69     0.00     1080   0 EMT       

             0       0         4     0               0   0 Idle    

               16     2360      8676 ...87     0.13     344   0 lsass     

               15   585040     449588     626     0.33   228     0 mysqld       

 

Step 9: create a database for Wordpress

 

Run the following command from C:\MySql\bin directory in order to create a new database which will be used by Wordpress:

.\mysql.exe -u root -e "create database nanoserver1_wordpress"

 

This screenshot shows how to create a new database and list up existing databases. I assume you used an empty password for the "root" database user. Otherwise, you will have to specify the password as well.

[nano1]: PS C:\> cd .\MySql\bin

[nano1]: PS C:\MySql\bin> .\mysql.exe -u root -e "create database nanoserver1_wordpress"

[nano1]: PS C:\MySql\bin> .\mysql.exe -u root -e "show databases;"

Database

information_schema

mysql

nanoserver1_wordpress

performance_schema

test

 

Step 10: configure PHP for MySQL

 

Create a new php.ini file under c:\php directory with the following file content:

 

[PHP]

extension_dir=c:\php\ext

extension=php_mysqli.dll

 

This screenshot shows how I created the file with psedit and how I checked the file path.

[nano1]: PS C:\> cd .\php

[nano1]: PS C:\php> new-item php.ini

 

    Directory: C:\php

 

Mode               LastWriteTime         Length Name                                              

----               -------------         ------ ----                                  

-a----         12/14/2015   6:05 PM             0 php.ini            

 

[nano1]: PS C:\php> psedit php.ini

### Here you have to save the php.ini file with the above file content

[nano1]: PS C:\php> type .\php.ini

[PHP]

extension_dir=c:\php\ext

extension=php_mysqli.dll

 

[nano1]: PS C:\php> dir C:\php\ext\php_mysqli.dll

    Directory: C:\php\ext

Mode               LastWriteTime         Length Name                                                                                                                                              

----               -------------         ------ ----                                                      

-a----         12/14/2015 11:47 AM         131072 php_mysqli.dll    

 

Step 11: install Wordpress package on Nano server

 

In this step, you will install Wordpress on your Nano server.

Go to https://wordpress.org/ and download the latest package file such as wordpress-4.3.1.zip.

Unzip the downloaded zip file and copy the contents to a directory such as c:\wordpress of your Nano server machine.

 

Your c:\wordpress directory structure should be like this:

[nano1]: PS C:\wordpress> dir

    Directory: C:\wordpress

Mode               LastWriteTime         Length Name 

----               -------------         ------ ----                                                                                      

d-----         12/14/2015   6:11 PM               wp-admin   

d-----         12/14/2015   6:11 PM               wp-content                 

d-----         12/14/2015   6:12 PM              wp-includes 

-a----         9/3/2015   3:33 AM           418 index.php                          

-a----         9/3/2015   3:33 AM         19930 license.txt   

-a----       9/15/2015   2:26 PM           7360 readme.html       

-a----         9/3/2015   3:33 AM           4951 wp-activate.php  

 

Now create wp-config.php file on c:\wordpress directory with the following file content:

 

<?php

define('DB_NAME', 'nanoserver1_wordpress');

define('DB_USER', 'root');

define('DB_PASSWORD', '');

define('DB_HOST', 'localhost');

define('DB_CHARSET', 'utf8');

define('DB_COLLATE', '');

define('AUTH_KEY',         'put your unique phrase here');

define('SECURE_AUTH_KEY', 'put your unique phrase here');

define('LOGGED_IN_KEY',   'put your unique phrase here');

define('NONCE_KEY',      'put your unique phrase here');

define('AUTH_SALT',       'put your unique phrase here');

define('SECURE_AUTH_SALT', 'put your unique phrase here');

define('LOGGED_IN_SALT',   'put your unique phrase here');

define('NONCE_SALT',       'put your unique phrase here');

$table_prefix = 'wp_';

define('WP_DEBUG', false);

if ( !defined('ABSPATH') )

define('ABSPATH', dirname(__FILE__) . '/');

require_once(ABSPATH . 'wp-settings.php');

 

The screenshot below shows how I created the file with the psedit tool. It also shows the content of the file with the "type .\wp-config.php" command. 

[nano1]: PS C:\> cd .\wordpress

[nano1]: PS C:\wordpress> new-item wp-config.php

    Directory: C:\wordpress

Mode               LastWriteTime         Length Name                                                          

----               -------------         ------ ----                                                          

-a----         12/14/2015   6:19 PM             0 wp-config.php                                                  

                                                                                    

[nano1]: PS C:\wordpress> psedit .\wp-config.php

### Here you have to save the wp-config.php file with the above file content

[nano1]: PS C:\wordpress> type .\wp-config.php

<?php

define('DB_NAME', 'nanoserver1_wordpress');

define('DB_USER', 'root');

define('DB_PASSWORD', '');

define('DB_HOST', 'localhost');

define('DB_CHARSET', 'utf8');

define('DB_COLLATE', '');

define('AUTH_KEY',         'put your unique phrase here');

define('SECURE_AUTH_KEY', 'put your unique phrase here');

define('LOGGED_IN_KEY',   'put your unique phrase here');

define('NONCE_KEY',       'put your unique phrase here');

define('AUTH_SALT',       'put your unique phrase here');

define('SECURE_AUTH_SALT', 'put your unique phrase here');

define('LOGGED_IN_SALT',   'put your unique phrase here');

define('NONCE_SALT',       'put your unique phrase here');

$table_prefix = 'wp_';

define('WP_DEBUG', false);

if ( !defined('ABSPATH') )

define('ABSPATH', dirname(__FILE__) . '/');

require_once(ABSPATH . 'wp-settings.php');

 

[jhkim-nano1]: PS C:\wordpress>

 

Step 12: configure Default Web Site

 

Open the applicationhost.config file which is placed in c:\windows\system32\inersrv\config and edit the physicalPath of the Default Web Site with "c:\wordpress".

 

Run

 

Now you are ready to start. In this section you will learn how to initialize Wordpress and use it.

 

Step 13: start http://<ComputerName>/wp-admin/install.php

 

Restart IIS services first. You can use the commands "Stop-Service was -Force -Confirm:$false" and "Start-Service w3svc".

Now you are ready to start.

On any client machine from which you can connect to your Nano server machine, open a web browser such as IE and browse http://<ComputerName>/wp-admin/install.php (NOTE: replace <ComputerName> with the computer name of your Nano server) and you will see a page which shows the list of language names.  

Select "English (United States)" and click Continue and now you will see the Welcome page. Fill in the form as you want to and click the "Install Wordpress" button.

And you will see the "Success!" page which has the "Log In" button.

Click the "Log In" button.

Type the user name and password that you used in the previous steps and click the "Log In" button.

If everything is okay, you will get to the Word press page.

 

Enhance PHP performance with WinCache

 

If you want better performance for the Wordpress web site or any PHP web sites running on IIS, you should use WinCache.

Here I will show how to install WinCache on Nano server and verify how it works.

 

Step 14: Install WinCache

 

Go to http://sourceforge.net/projects/wincache/files/development/wincache-2.0.0.2-dev-7.0-nts-vc14-x64.exe/download and download the latest 64 bit WinCache.

The file name will be like wincache-2.0.0.2-dev-7.0-nts-vc14-x64.exe.

Execute the downloaded file in order to unzip files in it.

Assuming you have installed PHP on c:\php directory, copy php_wincache.dll onto c:\php\ext directory of your Nano machine.

Edit c:\php\php.ini and add the line below.

 

extension=php_wincache.dll

 

This screenshot shows how I verified that the file has been correctly copied.

[nano1]: PS C:\php> dir .\ext\php_wincache.dll

    Directory: C:\php\ext

Mode               LastWriteTime         Length Name                                                          

----               -------------         ------ ----                                                          

-a----         10/30/2015 12:02 PM         143360 php_wincache.dll   

 

[nano1]: PS C:\php> type .\php.ini

[PHP]

extension_dir=c:\php\ext

extension=php_mysqli.dll

extension=php_wincache.dll

 

[jhkim-nano1]: PS C:\php>

 

Step 15: Verify WinCache

 

One easy way to verify PHP and Wincache is to simply run "php.exe --ini" and make sure there is no error.

 

This screenshot shows the example of running ".\php.exe --ini".

[nano1]: PS C:\php> .\php.exe --ini

Configuration File (php.ini) Path: C:\Windows

Loaded Configuration File:         C:\php\php.ini

Scan for additional .ini files in: (none)

Additional .ini files parsed:     (none)

 

Another way to verify is to use wincache2.php, which is one of files installed by the WinCache.

Copy wincache2.php onto the root directory of your web site such as c:\wordpress. 

Edit wincache2.php and change the value of USE_AUTHENTICAITION with 0 like the following:

 

FROM:

...

define('USE_AUTHENTICATION', 1);

 

TO:

...

define('USE_AUTHENTICATION', 0);

 

If you don't change the value of USE_AUTHENTICATION, you will see some error message regarding authentication.

 

Okay, now you are ready to run the php file.

Open a web browser and browse http://<ComputerName>/wincache2.php (NOTE: replace <ComputerName> with your machine name).

You will see the “Windows Cache Extension for PHP – Statistics” page and that Wincache is working correctly on your Nano server machine.

 

Viewing all 23 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>