├── .github
└── CODEOWNERS
├── .gitignore
├── .gitmodules
├── .pipelines
├── iis.servicemonitor.build.dev.yml
└── iis.servicemonitor.build.official.yml
├── Directory.Build.props
├── LICENSE
├── NuGet.config
├── README.md
├── SECURITY.md
├── ServiceMonitor.sln
├── azure-pipelines.yml
├── build.cmd
├── build
└── Build.Settings.targets
├── root.props
├── sign.props
└── src
└── ServiceMonitor
├── IISConfigUtil.cpp
├── IISConfigUtil.h
├── Main.cpp
├── ServiceMonitor.cpp
├── ServiceMonitor.h
├── ServiceMonitor.rc
├── ServiceMonitor.vcxproj
├── packages.config
├── stdafx.cpp
├── stdafx.h
├── targetver.h
└── version.h
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @Microsoft/iis-contributor
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # MSTest test Results
33 | [Tt]est[Rr]esult*/
34 | [Bb]uild[Ll]og.*
35 |
36 | # NUNIT
37 | *.VisualState.xml
38 | TestResult.xml
39 |
40 | # Build Results of an ATL Project
41 | [Dd]ebugPS/
42 | [Rr]eleasePS/
43 | dlldata.c
44 |
45 | # .NET Core
46 | project.lock.json
47 | project.fragment.lock.json
48 | artifacts/
49 | **/Properties/launchSettings.json
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # Visual Studio code coverage results
117 | *.coverage
118 | *.coveragexml
119 |
120 | # NCrunch
121 | _NCrunch_*
122 | .*crunch*.local.xml
123 | nCrunchTemp_*
124 |
125 | # MightyMoose
126 | *.mm.*
127 | AutoTest.Net/
128 |
129 | # Web workbench (sass)
130 | .sass-cache/
131 |
132 | # Installshield output folder
133 | [Ee]xpress/
134 |
135 | # DocProject is a documentation generator add-in
136 | DocProject/buildhelp/
137 | DocProject/Help/*.HxT
138 | DocProject/Help/*.HxC
139 | DocProject/Help/*.hhc
140 | DocProject/Help/*.hhk
141 | DocProject/Help/*.hhp
142 | DocProject/Help/Html2
143 | DocProject/Help/html
144 |
145 | # Click-Once directory
146 | publish/
147 |
148 | # Publish Web Output
149 | *.[Pp]ublish.xml
150 | *.azurePubxml
151 | # TODO: Comment the next line if you want to checkin your web deploy settings
152 | # but database connection strings (with potential passwords) will be unencrypted
153 | *.pubxml
154 | *.publishproj
155 |
156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
157 | # checkin your Azure Web App publish settings, but sensitive information contained
158 | # in these scripts will be unencrypted
159 | PublishScripts/
160 |
161 | # NuGet Packages
162 | *.nupkg
163 | # The packages folder can be ignored because of Package Restore
164 | **/packages/*
165 | # except build/, which is used as an MSBuild target.
166 | !**/packages/build/
167 | # Uncomment if necessary however generally it will be regenerated when needed
168 | #!**/packages/repositories.config
169 | # NuGet v3's project.json files produces more ignorable files
170 | *.nuget.props
171 | *.nuget.targets
172 |
173 | # Microsoft Azure Build Output
174 | csx/
175 | *.build.csdef
176 |
177 | # Microsoft Azure Emulator
178 | ecf/
179 | rcf/
180 |
181 | # Windows Store app package directories and files
182 | AppPackages/
183 | BundleArtifacts/
184 | Package.StoreAssociation.xml
185 | _pkginfo.txt
186 |
187 | # Visual Studio cache files
188 | # files ending in .cache can be ignored
189 | *.[Cc]ache
190 | # but keep track of directories ending in .cache
191 | !*.[Cc]ache/
192 |
193 | # Others
194 | ClientBin/
195 | ~$*
196 | *~
197 | *.dbmdl
198 | *.dbproj.schemaview
199 | *.jfm
200 | *.pfx
201 | *.publishsettings
202 | orleans.codegen.cs
203 |
204 | # Since there are multiple workflows, uncomment next line to ignore bower_components
205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
206 | #bower_components/
207 |
208 | # RIA/Silverlight projects
209 | Generated_Code/
210 |
211 | # Backup & report files from converting an old project file
212 | # to a newer Visual Studio version. Backup files are not needed,
213 | # because we have git ;-)
214 | _UpgradeReport_Files/
215 | Backup*/
216 | UpgradeLog*.XML
217 | UpgradeLog*.htm
218 |
219 | # SQL Server files
220 | *.mdf
221 | *.ldf
222 | *.ndf
223 |
224 | # Business Intelligence projects
225 | *.rdl.data
226 | *.bim.layout
227 | *.bim_*.settings
228 |
229 | # Microsoft Fakes
230 | FakesAssemblies/
231 |
232 | # GhostDoc plugin setting file
233 | *.GhostDoc.xml
234 |
235 | # Node.js Tools for Visual Studio
236 | .ntvs_analysis.dat
237 | node_modules/
238 |
239 | # Typescript v1 declaration files
240 | typings/
241 |
242 | # Visual Studio 6 build log
243 | *.plg
244 |
245 | # Visual Studio 6 workspace options file
246 | *.opt
247 |
248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
249 | *.vbw
250 |
251 | # Visual Studio LightSwitch build output
252 | **/*.HTMLClient/GeneratedArtifacts
253 | **/*.DesktopClient/GeneratedArtifacts
254 | **/*.DesktopClient/ModelManifest.xml
255 | **/*.Server/GeneratedArtifacts
256 | **/*.Server/ModelManifest.xml
257 | _Pvt_Extensions
258 |
259 | # Paket dependency manager
260 | .paket/paket.exe
261 | paket-files/
262 |
263 | # FAKE - F# Make
264 | .fake/
265 |
266 | # JetBrains Rider
267 | .idea/
268 | *.sln.iml
269 |
270 | # CodeRush
271 | .cr/
272 |
273 | # Python Tools for Visual Studio (PTVS)
274 | __pycache__/
275 | *.pyc
276 |
277 | # Cake - Uncomment if you are using it
278 | # tools/**
279 | # !tools/packages.config
280 |
281 | # Telerik's JustMock configuration file
282 | *.jmconfig
283 |
284 | # BizTalk build output
285 | *.btp.cs
286 | *.btm.cs
287 | *.odx.cs
288 | *.xsd.cs
289 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "IIS.Common"]
2 | path = IIS.Common
3 | url = https://github.com/Microsoft/IIS.Common.git
4 |
--------------------------------------------------------------------------------
/.pipelines/iis.servicemonitor.build.dev.yml:
--------------------------------------------------------------------------------
1 | name: $(Rev:rr)
2 |
3 | pr:
4 | - master
5 |
6 | trigger:
7 | batch: true
8 | branches:
9 | include:
10 | - master
11 |
12 | resources:
13 | repositories:
14 | - repository: MicrosoftIISCommon
15 | type: github
16 | name: Microsoft/IIS.Common
17 | endpoint: GitHub-IIS-Token
18 |
19 | jobs:
20 | - template: .azure\templates\build.yml@MicrosoftIISCommon
21 | parameters:
22 | agentPoolName: 'VSEngSS-MicroBuild2022-1ES'
23 | agentPoolDemandTeam: ''
24 | solution: '**\ServiceMonitor.sln'
25 | productMajor: 2
26 | productMinor: 0
27 | buildMinor: $(Build.BuildNumber)
28 | signType: 'test'
29 | indexSourcesAndPublishSymbols: 'true'
30 | publishArtifactInstallers: 'false'
31 | whiteListPathForAuthenticodeSign: '$(Build.SourcesDirectory)\IIS-Common\.azure\templates\no_authenticode.txt'
32 |
33 |
--------------------------------------------------------------------------------
/.pipelines/iis.servicemonitor.build.official.yml:
--------------------------------------------------------------------------------
1 | name: $(Rev:rr)
2 |
3 | pr: none
4 | trigger: none
5 |
6 | resources:
7 | repositories:
8 | - repository: MicrosoftIISCommon
9 | type: github
10 | name: Microsoft/IIS.Common
11 | endpoint: GitHub-IIS-Token
12 |
13 | jobs:
14 | - template: .azure\templates\build.yml@MicrosoftIISCommon
15 | parameters:
16 | agentPoolName: 'VSEngSS-MicroBuild2022-1ES'
17 | agentPoolDemandTeam: ''
18 | solution: '**\ServiceMonitor.sln'
19 | productMajor: 1
20 | productMinor: 0
21 | buildMinor: $(Build.BuildNumber)
22 | signType: 'real'
23 | indexSourcesAndPublishSymbols: 'true'
24 | publishArtifactInstallers: 'false'
25 | whiteListPathForAuthenticodeSign: '$(Build.SourcesDirectory)\IIS-Common\.azure\templates\no_authenticode.txt'
26 |
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Microsoft Corporation. All rights reserved.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE
22 |
--------------------------------------------------------------------------------
/NuGet.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Microsoft IIS Service Monitor
2 |
3 | **ServiceMonitor** is a Windows executable designed to be used as the entrypoint
4 | process when running IIS inside a Windows Server container.
5 |
6 | ServiceMonitor monitors the status of the `w3svc` service and will exit when the
7 | service state changes from `SERVICE_RUNNING` to either one of `SERVICE_STOPPED`,
8 | `SERVICE_STOP_PENDING`, `SERVICE_PAUSED` or `SERVICE_PAUSE_PENDING`.
9 |
10 | Additionally, ServiceMonitor will promote environment variables from process
11 | environment it's own process environment block to the DefaultAppPool. We achieve
12 | this by naively copying all variables in our process environment block except
13 | for those Environment variable / value pairs present in this list below.
14 |
15 | ### Environment variable exclusion list
16 |
17 | | Environment Variable | Value |
18 | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
19 | | TMP | "C:\\Users\\ContainerAdministrator\\AppData\\Local\\Temp" |
20 | | TEMP | "C:\\Users\\ContainerAdministrator\\AppData\\Local\\Temp" |
21 | | USERNAME | "ContainerAdministrator" |
22 | | USERPROFILE | "C:\\Users\\ContainerAdministrator" |
23 | | APPDATA | "C:\\Users\\ContainerAdministrator\\AppData\\Roaming" |
24 | | LOCALAPPDATA | "C:\\Users\\ContainerAdministrator\\AppData\\Local" |
25 | | PROGRAMDATA | "C:\\ProgramData" |
26 | | PSMODULEPATH | "%ProgramFiles%\\WindowsPowerShell\\Modules;C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\Modules" |
27 | | PUBLIC | "C:\\Users\\Public" |
28 | | USERDOMAIN | "User Manager" |
29 | | ALLUSERSPROFILE | "C:\\ProgramData" |
30 | | PATHEXT | ".COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC" |
31 | | PATH | * |
32 | | COMPUTERNAME | * |
33 | | COMSPEC | * |
34 | | OS | * |
35 | | PROCESSOR_IDENTIFIER | * |
36 | | PROCESSOR_LEVEL | * |
37 | | PROCESSOR_REVISION | * |
38 | | PROGRAMFILES | * |
39 | | PROGRAMFILES(X86) | * |
40 | | PROGRAMW6432 | * |
41 | | SYSTEMDRIVE | * |
42 | | WINDIR | * |
43 | | NUMBER_OF_PROCESSORS | * |
44 | | PROCESSOR_ARCHITECTURE | * |
45 | | SYSTEMROOT | * |
46 | | COMMONPROGRAMFILES | * |
47 | | COMMONPROGRAMFILES(X86) | * |
48 | | COMMONPROGRAMW6432 | * |
49 | | DRIVERDATA | * |
50 |
51 | ## Build
52 |
53 | ```
54 | .\build.cmd
55 | ```
56 |
57 | ## Usage
58 |
59 | ```
60 | .\ServiceMonitor.exe w3svc
61 | ```
62 |
63 | ServiceMonitor is currently distributed as part of the [IIS](https://hub.docker.com/_/microsoft-windows-servercore-iis),
64 | [ASP.NET](https://hub.docker.com/_/microsoft-dotnet-framework-aspnet), and [WCF](https://hub.docker.com/_/microsoft-dotnet-framework-wcf) images on Docker Hub. We recommend layering your project on top of those official images as running
65 | ServiceMonitor directly in your Dockerfile.
66 |
67 | ## Contributing
68 |
69 | This project welcomes contributions and suggestions. Most contributions require
70 | you to agree to a Contributor License Agreement (CLA) declaring that you have
71 | the right to, and actually do, grant us the rights to use your contribution. For
72 | details, visit https://cla.microsoft.com.
73 |
74 | When you submit a pull request, a CLA-bot will automatically determine whether
75 | you need to provide a CLA and decorate the PR appropriately (e.g., label,
76 | comment). Simply follow the instructions provided by the bot. You will only need
77 | to do this once across all repos using our CLA.
78 |
79 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
80 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
81 | or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any
82 | additional questions or comments.
83 |
84 |
85 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Security
4 |
5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
6 |
7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
8 |
9 | ## Reporting Security Issues
10 |
11 | **Please do not report security vulnerabilities through public GitHub issues.**
12 |
13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
14 |
15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
16 |
17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
18 |
19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
20 |
21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
22 | * Full paths of source file(s) related to the manifestation of the issue
23 | * The location of the affected source code (tag/branch/commit or direct URL)
24 | * Any special configuration required to reproduce the issue
25 | * Step-by-step instructions to reproduce the issue
26 | * Proof-of-concept or exploit code (if possible)
27 | * Impact of the issue, including how an attacker might exploit the issue
28 |
29 | This information will help us triage your report more quickly.
30 |
31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
32 |
33 | ## Preferred Languages
34 |
35 | We prefer all communications to be in English.
36 |
37 | ## Policy
38 |
39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
40 |
41 |
42 |
--------------------------------------------------------------------------------
/ServiceMonitor.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.26717.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{1F39DB32-3422-4FF2-A8A4-A4BCCB0FD36E}"
7 | EndProject
8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ServiceMonitor", "src\ServiceMonitor\ServiceMonitor.vcxproj", "{EFAE236B-EFB4-413C-8EEE-09F211558AC1}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|x64 = Debug|x64
13 | Debug|x86 = Debug|x86
14 | Release|x64 = Release|x64
15 | Release|x86 = Release|x86
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {EFAE236B-EFB4-413C-8EEE-09F211558AC1}.Debug|x64.ActiveCfg = Debug|x64
19 | {EFAE236B-EFB4-413C-8EEE-09F211558AC1}.Debug|x64.Build.0 = Debug|x64
20 | {EFAE236B-EFB4-413C-8EEE-09F211558AC1}.Debug|x86.ActiveCfg = Debug|Win32
21 | {EFAE236B-EFB4-413C-8EEE-09F211558AC1}.Debug|x86.Build.0 = Debug|Win32
22 | {EFAE236B-EFB4-413C-8EEE-09F211558AC1}.Release|x64.ActiveCfg = Release|x64
23 | {EFAE236B-EFB4-413C-8EEE-09F211558AC1}.Release|x64.Build.0 = Release|x64
24 | {EFAE236B-EFB4-413C-8EEE-09F211558AC1}.Release|x86.ActiveCfg = Release|Win32
25 | {EFAE236B-EFB4-413C-8EEE-09F211558AC1}.Release|x86.Build.0 = Release|Win32
26 | EndGlobalSection
27 | GlobalSection(SolutionProperties) = preSolution
28 | HideSolutionNode = FALSE
29 | EndGlobalSection
30 | GlobalSection(NestedProjects) = preSolution
31 | {EFAE236B-EFB4-413C-8EEE-09F211558AC1} = {1F39DB32-3422-4FF2-A8A4-A4BCCB0FD36E}
32 | EndGlobalSection
33 | GlobalSection(ExtensibilityGlobals) = postSolution
34 | SolutionGuid = {DEE383BB-40C7-47B7-84D9-91DDD29A8297}
35 | EndGlobalSection
36 | EndGlobal
37 |
--------------------------------------------------------------------------------
/azure-pipelines.yml:
--------------------------------------------------------------------------------
1 | resources:
2 | repositories:
3 | - repository: Microsoft/IIS.Common
4 | type: github
5 | name: Microsoft/IIS.Common
6 | endpoint: GitHub-IIS-PAT
7 |
8 | jobs:
9 | - template: azure-pipelines.yml@Microsoft/IIS.Common # Template reference
10 |
--------------------------------------------------------------------------------
/build.cmd:
--------------------------------------------------------------------------------
1 | msbuild ServiceMonitor.sln /p:platform=x64 /p:configuration=Release
--------------------------------------------------------------------------------
/build/Build.Settings.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 | x64
4 | x86
5 |
6 |
--------------------------------------------------------------------------------
/root.props:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 | $(MSBuildThisFileDirectory)
9 | $(RepositoryRoot)src
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/sign.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 0.2.0
5 |
6 |
7 |
8 |
9 | $(SigningIdentity)
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/ServiceMonitor/IISConfigUtil.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license.
3 |
4 | #include"stdafx.h"
5 | #include
6 | using namespace std;
7 |
8 | #define APPCMD_MAX_SIZE 30000
9 | #define KV(a,b) pair(a,b)
10 | #define KV_WSTR(a,b) pair(a,b)
11 | #define POPULATE(map) do \
12 | { \
13 | map.insert(KV(L"TMP", L"C:\\Users\\ContainerAdministrator\\AppData\\Local\\Temp")); \
14 | map.insert(KV(L"TEMP", L"C:\\Users\\ContainerAdministrator\\AppData\\Local\\Temp")); \
15 | map.insert(KV(L"USERNAME", L"ContainerAdministrator")); \
16 | map.insert(KV(L"USERPROFILE", L"C:\\Users\\ContainerAdministrator")); \
17 | map.insert(KV(L"APPDATA", L"C:\\Users\\ContainerAdministrator\\AppData\\Roaming")); \
18 | map.insert(KV(L"LOCALAPPDATA", L"C:\\Users\\ContainerAdministrator\\AppData\\Local")); \
19 | map.insert(KV(L"PROGRAMDATA", L"C:\\ProgramData")); \
20 | map.insert(KV(L"PSMODULEPATH", L"%ProgramFiles%\\WindowsPowerShell\\Modules;C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\Modules")); \
21 | map.insert(KV(L"PUBLIC", L"C:\\Users\\Public")); \
22 | map.insert(KV(L"USERDOMAIN", L"User Manager")); \
23 | map.insert(KV(L"ALLUSERSPROFILE", L"C:\\ProgramData")); \
24 | map.insert(KV(L"PATHEXT", L".COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC")); \
25 | map.insert(KV(L"PATH", NULL)); \
26 | map.insert(KV(L"COMPUTERNAME", NULL)); \
27 | map.insert(KV(L"COMSPEC", NULL)); \
28 | map.insert(KV(L"OS", NULL)); \
29 | map.insert(KV(L"PROCESSOR_IDENTIFIER", NULL)); \
30 | map.insert(KV(L"PROCESSOR_LEVEL", NULL)); \
31 | map.insert(KV(L"PROCESSOR_REVISION", NULL)); \
32 | map.insert(KV(L"PROGRAMFILES", NULL)); \
33 | map.insert(KV(L"PROGRAMFILES(X86)", NULL)); \
34 | map.insert(KV(L"PROGRAMW6432", NULL)); \
35 | map.insert(KV(L"SYSTEMDRIVE", NULL)); \
36 | map.insert(KV(L"WINDIR", NULL)); \
37 | map.insert(KV(L"NUMBER_OF_PROCESSORS", NULL)); \
38 | map.insert(KV(L"PROCESSOR_ARCHITECTURE", NULL)); \
39 | map.insert(KV(L"SYSTEMROOT", NULL)); \
40 | map.insert(KV(L"COMMONPROGRAMFILES", NULL)); \
41 | map.insert(KV(L"COMMONPROGRAMFILES(X86)", NULL)); \
42 | map.insert(KV(L"COMMONPROGRAMW6432", NULL)); \
43 | map.insert(KV(L"DRIVERDATA", NULL)); \
44 | } while(0)
45 |
46 | IISConfigUtil::IISConfigUtil():m_pstrSysDirPath(NULL)
47 | {
48 | }
49 |
50 | IISConfigUtil::~IISConfigUtil()
51 | {
52 | if (m_pstrSysDirPath != NULL)
53 | {
54 | delete m_pstrSysDirPath;
55 | m_pstrSysDirPath = NULL;
56 | }
57 | }
58 |
59 | BOOL IISConfigUtil::FilterEnv(const unordered_map& filter, LPCTSTR strEnvName, LPCTSTR strEnvValue)
60 | {
61 | LPTSTR strFilterValue;
62 | _ASSERT(strEnvName != NULL);
63 | _ASSERT(strEnvValue != NULL);
64 |
65 | auto value = filter.find(strEnvName);
66 |
67 | //
68 | // add this environment variable if the name does not match the block list
69 | //
70 | if (value == filter.end())
71 | {
72 | return FALSE;
73 | }
74 |
75 | strFilterValue = value->second;
76 |
77 | //
78 | // filter out this environment variable if
79 | // 1. value match is not required (strFilterValue is NULL)
80 | // 2. require value match and value matches
81 | //
82 | if ((strFilterValue == NULL ) || (lstrcmpi(strEnvValue, strFilterValue) == 0))
83 | {
84 | return TRUE;
85 | }
86 |
87 | return FALSE;
88 | }
89 |
90 | HRESULT IISConfigUtil::Initialize()
91 | {
92 | HRESULT hr = S_OK;
93 | TCHAR* pBuffer = NULL;
94 | DWORD dwBufSize = 0;
95 |
96 | //
97 | // resolve system drive
98 | //
99 | dwBufSize = GetSystemDirectory(NULL, 0);
100 | if (dwBufSize == 0)
101 | {
102 | //
103 | // failed to get System Directory info
104 | //
105 | hr = HRESULT_FROM_WIN32(GetLastError());
106 | goto Finished;
107 | }
108 |
109 | pBuffer = (TCHAR*)malloc(dwBufSize * sizeof(TCHAR));
110 | if (pBuffer == NULL)
111 | {
112 | hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
113 | goto Finished;
114 | }
115 |
116 | if (GetSystemDirectory(pBuffer, dwBufSize) == 0)
117 | {
118 | hr = HRESULT_FROM_WIN32(GetLastError());
119 | goto Finished;
120 | }
121 |
122 | m_pstrSysDirPath = pBuffer;
123 | pBuffer = NULL;
124 |
125 | Finished:
126 | if (pBuffer != NULL)
127 | {
128 | free(pBuffer);
129 | pBuffer = NULL;
130 | }
131 | return hr;
132 | }
133 |
134 | void IISConfigUtil::Replace(std::wstring& str, std::wstring oldValue, std::wstring newValue)
135 | {
136 | size_t pos = 0;
137 | size_t oldValueLen = oldValue.length();
138 | size_t newValueLen = newValue.length();
139 |
140 | while ((pos = str.find(oldValue, pos)) != std::wstring::npos) {
141 | str.replace(pos, oldValueLen, newValue);
142 | pos += newValueLen;
143 | }
144 | }
145 |
146 | HRESULT IISConfigUtil::BuildAppCmdCommand(const vector>& vecSet, vector>::iterator& envVecIter, WCHAR* pstrAppPoolName, wstring& pStrCmd, APPCMD_CMD_TYPE appCmdType)
147 | {
148 | HRESULT hr = S_OK;
149 | _ASSERT(pstrAppPoolName != NULL);
150 |
151 | pStrCmd.append(m_pstrSysDirPath);
152 | pStrCmd.append(L"\\inetsrv\\appcmd.exe set config -section:system.applicationHost/applicationPools ");
153 |
154 | for (; envVecIter != vecSet.end(); envVecIter++)
155 | {
156 | wstring strEnvName = envVecIter->first;
157 | wstring strEnvValue = envVecIter->second;
158 |
159 | //
160 | // Handle values that have single and double quotes
161 | //
162 | Replace(strEnvName, L"'", L"''");
163 | Replace(strEnvName, L"\"", L"\"\"\"");
164 | Replace(strEnvValue, L"'", L"''");
165 | Replace(strEnvValue, L"\"", L"\"\"\"");
166 |
167 | if ((pStrCmd.length() + strEnvName.length() + strEnvValue.length()) > APPCMD_MAX_SIZE)
168 | {
169 | //
170 | // caller need to call again
171 | //
172 |
173 | hr = ERROR_MORE_DATA;
174 | break;
175 | }
176 |
177 | if (appCmdType == APPCMD_ADD)
178 | {
179 | pStrCmd.append(L"/+\"[name='");
180 | }
181 | else
182 | {
183 | pStrCmd.append(L"/-\"[name='");
184 | }
185 | pStrCmd.append(pstrAppPoolName);
186 | pStrCmd.append(L"'].environmentVariables.[name='");
187 | pStrCmd.append(strEnvName);
188 | if (appCmdType == APPCMD_ADD)
189 | {
190 | pStrCmd.append(L"',value='");
191 | pStrCmd.append(strEnvValue);
192 | }
193 | pStrCmd.append(L"']\" ");
194 | }
195 |
196 | pStrCmd.append(L" /commit:apphost");
197 |
198 | return hr;
199 | }
200 |
201 |
202 | HRESULT IISConfigUtil::RunCommand(wstring& pstrCmd, BOOL fIgnoreError)
203 | {
204 | HRESULT hr = S_OK;
205 | STARTUPINFO si = { sizeof(STARTUPINFO) };
206 | DWORD dwStatus = 0;
207 | PROCESS_INFORMATION pi;
208 |
209 | ZeroMemory(&si, sizeof(STARTUPINFO));
210 | si.cb = sizeof(STARTUPINFO);
211 | si.dwFlags |= STARTF_USESTDHANDLES;
212 |
213 | if (!CreateProcess(NULL,
214 | (LPWSTR)pstrCmd.c_str(),
215 | NULL,
216 | NULL,
217 | false,
218 | 0,
219 | NULL,
220 | NULL,
221 | &si,
222 | &pi))
223 | {
224 | hr = HRESULT_FROM_WIN32(GetLastError());
225 | goto Finished;
226 | }
227 |
228 | //
229 | // wait for at most 5 seconds to allow APPCMD finish
230 | //
231 | WaitForSingleObject(pi.hProcess, 5000);
232 | if ((!GetExitCodeProcess(pi.hProcess, &dwStatus) || dwStatus != 0) && (!fIgnoreError))
233 | {
234 | //
235 | // appcmd command failed
236 | //
237 | _tprintf(L"\nAPPCMD failed with error code %d\n", dwStatus);
238 | hr = E_FAIL;
239 | }
240 |
241 | CloseHandle(pi.hProcess);
242 | CloseHandle(pi.hThread);
243 |
244 | Finished:
245 |
246 | return hr;
247 | }
248 |
249 | HRESULT IISConfigUtil::UpdateEnvironmentVarsToConfig(WCHAR* pstrAppPoolName)
250 | {
251 | HRESULT hr = S_OK;
252 | LPTCH lpvEnv = NULL;
253 | LPTSTR lpszVariable = NULL;
254 | wstring pstrAddCmd;
255 | wstring pstrRmCmd;
256 | BOOL fMoreData = TRUE;
257 |
258 | unordered_map filter;
259 | vector> envVec;
260 | vector>::iterator envVecIter;
261 |
262 | POPULATE(filter) ;
263 |
264 | lpvEnv = GetEnvironmentStrings();
265 | if (lpvEnv == NULL)
266 | {
267 | _tprintf(L"Failed to call GetEnvironmentStrings! \n");
268 | hr = E_FAIL;
269 | goto Finished;
270 | }
271 |
272 | lpszVariable = (LPTSTR)lpvEnv;
273 | while (*lpszVariable)
274 | {
275 | LPTSTR pEqualChar = wcschr(lpszVariable, L'=');
276 | if (pEqualChar != lpszVariable)
277 | {
278 | DWORD dwStatus = 0;
279 | LPTSTR pstrValue = pEqualChar + 1;
280 | LPTSTR pstrName = lpszVariable;
281 |
282 |
283 | pEqualChar[0] = L'\0';
284 | wstring strNameCheck(pstrName);
285 | if (FilterEnv(filter, CharUpper((LPWSTR)strNameCheck.c_str()), pstrValue))
286 | {
287 | pEqualChar[0] = L'=';
288 | lpszVariable += lstrlen(lpszVariable) + 1;
289 |
290 | continue;
291 | }
292 |
293 | envVec.emplace_back(wstring(pstrName), wstring(pstrValue));
294 |
295 | pEqualChar[0] = L'=';
296 |
297 | }
298 | //
299 | // move to next environment variable
300 | //
301 | lpszVariable += lstrlen(lpszVariable) + 1;
302 | }
303 |
304 | envVecIter = envVec.begin();
305 | while (fMoreData)
306 | {
307 |
308 | pstrRmCmd.clear();
309 | fMoreData = FALSE;
310 | hr = BuildAppCmdCommand(envVec, envVecIter, pstrAppPoolName, pstrRmCmd, APPCMD_RM);
311 |
312 | if (hr != ERROR_MORE_DATA && FAILED(hr))
313 | {
314 | goto Finished;
315 | }
316 |
317 | if (hr == ERROR_MORE_DATA)
318 | {
319 | hr = S_OK;
320 | fMoreData = TRUE;
321 | }
322 |
323 | //
324 | //allow appcmd to fail if it is trying to remove environment variable
325 | //
326 | RunCommand(pstrRmCmd, TRUE);
327 | }
328 |
329 | fMoreData = TRUE;
330 | envVecIter = envVec.begin();
331 | while (fMoreData)
332 | {
333 | pstrAddCmd.clear();
334 | fMoreData = FALSE;
335 | hr = BuildAppCmdCommand(envVec, envVecIter, pstrAppPoolName, pstrAddCmd, APPCMD_ADD);
336 |
337 | if (hr != ERROR_MORE_DATA && FAILED(hr))
338 | {
339 | goto Finished;
340 | }
341 |
342 | if (hr == ERROR_MORE_DATA)
343 | {
344 | hr = S_OK;
345 | fMoreData = TRUE;
346 | }
347 |
348 | //
349 | //appcmd must succeed when add new environment variables
350 | //
351 | hr = RunCommand(pstrAddCmd, FALSE);
352 |
353 | if (FAILED(hr))
354 | {
355 | goto Finished;
356 | }
357 | }
358 |
359 | Finished:
360 | if (lpvEnv != NULL)
361 | {
362 | FreeEnvironmentStrings(lpvEnv);
363 | lpvEnv = NULL;
364 | }
365 |
366 | return hr;
367 | }
--------------------------------------------------------------------------------
/src/ServiceMonitor/IISConfigUtil.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license.
3 |
4 | #pragma once
5 |
6 | #include
7 | #include
8 |
9 | enum APPCMD_CMD_TYPE
10 | {
11 | APPCMD_ADD = 0,
12 | APPCMD_RM = 1
13 | };
14 |
15 | class IISConfigUtil
16 | {
17 | public:
18 |
19 | IISConfigUtil();
20 | ~IISConfigUtil();
21 | HRESULT Initialize();
22 | HRESULT UpdateEnvironmentVarsToConfig(WCHAR* pstrAppPoolName);
23 |
24 | private:
25 | HRESULT RunCommand(std::wstring& pstrCmd, BOOL fIgnoreError);
26 | void Replace(std::wstring& str, std::wstring oldValue, std::wstring newValue);
27 | HRESULT BuildAppCmdCommand(const std::vector>& vecSet, std::vector>::iterator& envVecIter, WCHAR* pstrAppPoolName, std::wstring& pStrCmd, APPCMD_CMD_TYPE appcmdType);
28 | BOOL FilterEnv(const std::unordered_map& filter, LPCTSTR strEnvName, LPCTSTR strEnvValue);
29 | TCHAR* m_pstrSysDirPath;
30 | };
31 |
32 |
--------------------------------------------------------------------------------
/src/ServiceMonitor/Main.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license.
3 |
4 | #include"stdafx.h"
5 |
6 | HANDLE g_hStopEvent = INVALID_HANDLE_VALUE;
7 |
8 | BOOL WINAPI CtrlHandle(DWORD dwCtrlType)
9 | {
10 | switch (dwCtrlType)
11 | {
12 | case CTRL_C_EVENT:
13 | case CTRL_CLOSE_EVENT:
14 | case CTRL_BREAK_EVENT:
15 | case CTRL_LOGOFF_EVENT:
16 | case CTRL_SHUTDOWN_EVENT:
17 | _tprintf(L"\nCTRL signal received. The process will now terminate.\n");
18 | SetEvent(g_hStopEvent);
19 | g_hStopEvent = INVALID_HANDLE_VALUE;
20 | break;
21 |
22 | default:
23 | break;
24 | }
25 |
26 | return TRUE;
27 | }
28 |
29 | int __cdecl _tmain(int argc, _TCHAR* argv[])
30 | {
31 | HRESULT hr = S_OK;
32 | Service_Monitor sm = Service_Monitor();
33 |
34 | if (argc <= 1)
35 | {
36 | _tprintf(L"\nUSAGE: %s [windows service name]", argv[0]);
37 | _tprintf(L"\n %s w3svc [application pool]", argv[0]);
38 | _tprintf(L"\n\nOptions:");
39 | _tprintf(L"\n windows service name Name of the Windows service to monitor");
40 | _tprintf(L"\n application pool Name of the application pool to monitor; defaults to DefaultAppPool\n");
41 | goto Finished;
42 | }
43 |
44 | // iis only allow monitor on w3svc
45 | if (_wcsicmp(argv[1], L"w3svc") == 0)
46 | {
47 | hr = sm.StopServiceByName(L"w3svc");
48 | if (FAILED(hr))
49 | {
50 | hr = HRESULT_FROM_WIN32(GetLastError());
51 | goto Finished;
52 | }
53 |
54 | //
55 | // iis scenario, update the environment variable
56 | // we hardcode this behavior for now. We can add an input switch later if needed
57 | //
58 | WCHAR* pstrAppPoolName = L"DefaultAppPool";
59 | if (argc > 2)
60 | {
61 | pstrAppPoolName = argv[2];
62 | }
63 | IISConfigUtil configHelper = IISConfigUtil();
64 | if( FAILED(hr = configHelper.Initialize()) ||
65 | FAILED(hr = configHelper.UpdateEnvironmentVarsToConfig(pstrAppPoolName)))
66 | {
67 | _tprintf(L"\nFailed to update IIS configuration\n");
68 | goto Finished;
69 | }
70 | }
71 |
72 | g_hStopEvent = CreateEvent(
73 | NULL, // default security attributes
74 | TRUE, // manual-reset event
75 | FALSE, // initial state is nonsignaled
76 | argv[1] // object name
77 | );
78 |
79 | if (g_hStopEvent == NULL)
80 | {
81 | hr = HRESULT_FROM_WIN32(GetLastError());
82 | goto Finished;
83 | }
84 |
85 | if (!SetConsoleCtrlHandler(CtrlHandle, TRUE))
86 | {
87 | hr = HRESULT_FROM_WIN32(GetLastError());
88 | _tprintf(L"\nERROR: Failed to set control handle with error [%x]\n", hr);
89 | goto Finished;
90 | }
91 |
92 | if (g_hStopEvent != INVALID_HANDLE_VALUE)
93 | {
94 | hr = sm.StartServiceByName(argv[1]);
95 | }
96 |
97 | if (SUCCEEDED(hr))
98 | {
99 | if (g_hStopEvent != INVALID_HANDLE_VALUE)
100 | {
101 | //
102 | // will stop monitoring once the stop event is set
103 | //
104 | hr = sm.MonitoringService(argv[1],
105 | SERVICE_NOTIFY_STOPPED | SERVICE_NOTIFY_STOP_PENDING | SERVICE_NOTIFY_PAUSED | SERVICE_NOTIFY_PAUSE_PENDING,
106 | g_hStopEvent);
107 | }
108 | }
109 | //
110 | // don't capture the stop error
111 | //
112 | sm.StopServiceByName(argv[1]);
113 |
114 | Finished:
115 | if (g_hStopEvent != INVALID_HANDLE_VALUE)
116 | {
117 | CloseHandle(g_hStopEvent);
118 | g_hStopEvent = INVALID_HANDLE_VALUE;
119 | }
120 | return hr;
121 | }
122 |
--------------------------------------------------------------------------------
/src/ServiceMonitor/ServiceMonitor.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license.
3 |
4 | // ServiceMonitor.cpp : Defines the entry point for the console application.
5 | //
6 | #include"stdafx.h"
7 |
8 | VOID CALLBACK Service_Monitor::NotifyCallBack(PVOID parameter)
9 | {
10 | PSERVICE_NOTIFY pSNotify = (PSERVICE_NOTIFY)parameter;
11 | HANDLE hEvent = (HANDLE) pSNotify->pContext;
12 | _tprintf(L"\nService Change Status Notify Callback is called for service '%s' with status '%d'",
13 | pSNotify->pszServiceNames, pSNotify->ServiceStatus.dwCurrentState);
14 | if (hEvent != NULL)
15 | {
16 | SetEvent(hEvent);
17 | }
18 | }
19 |
20 | HRESULT Service_Monitor::EnsureInitialized()
21 | {
22 | HRESULT hr = S_OK;
23 | if (!_fInitialized)
24 | {
25 | AcquireSRWLockExclusive(&_srwLock);
26 | if (!_fInitialized)
27 | {
28 | _hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
29 | if (_hSCManager == NULL)
30 | {
31 | hr = HRESULT_FROM_WIN32(GetLastError());
32 | _tprintf(L"\nERROR:Could NOT open server control manager [%x]\n", hr);
33 | }
34 | else
35 | {
36 | _fInitialized = TRUE;
37 | }
38 | }
39 | ReleaseSRWLockExclusive(&_srwLock);
40 | }
41 | return hr;
42 | }
43 |
44 | HRESULT Service_Monitor::StartServiceByName(LPCTSTR pServiceName, DWORD dwTimeOutSeconds)
45 | {
46 | HRESULT hr = S_OK;
47 | SC_HANDLE hService = NULL;
48 | DWORD dwSleepTime = 0;
49 | DWORD dwRemainTime = dwTimeOutSeconds;
50 |
51 | hr = GetServiceHandle(pServiceName, &hService);
52 |
53 | if (SUCCEEDED(hr))
54 | {
55 | if (StartService(hService, 0, NULL) == FALSE)
56 | {
57 | DWORD dwError = GetLastError();
58 | if (dwError == ERROR_SERVICE_ALREADY_RUNNING)
59 | {
60 | dwError = ERROR_SUCCESS;
61 | }
62 | else
63 | {
64 | hr = HRESULT_FROM_WIN32(dwError);
65 | }
66 | }
67 | //
68 | // Query service status to make sure service is in running state
69 | //
70 | while(dwRemainTime >0)
71 | {
72 | DWORD dwBytes = 0;
73 | SERVICE_STATUS_PROCESS sStatus;
74 |
75 | if (!QueryServiceStatusEx(hService,
76 | SC_STATUS_PROCESS_INFO,
77 | (LPBYTE)&sStatus,
78 | sizeof(SERVICE_STATUS_PROCESS),
79 | &dwBytes))
80 | {
81 | hr = HRESULT_FROM_WIN32(GetLastError());
82 | goto Finished;
83 | }
84 |
85 | if (sStatus.dwCurrentState == SERVICE_RUNNING)
86 | {
87 | goto Finished;
88 | }
89 | else if(sStatus.dwCurrentState == SERVICE_START_PENDING)
90 | {
91 | dwSleepTime = rand() % 10 + 1;
92 | dwSleepTime = dwSleepTime < dwRemainTime ? dwSleepTime : dwRemainTime;
93 | dwRemainTime -= dwSleepTime;
94 | Sleep(dwSleepTime * 1000);
95 | }
96 | else
97 | {
98 | //
99 | // Service fails to start
100 | //
101 | hr = E_FAIL;
102 | goto Finished;
103 | }
104 | }
105 | //
106 | // Cannot start service within given time period
107 | //
108 | hr = HRESULT_FROM_WIN32(ERROR_TIMEOUT);
109 | }
110 |
111 | Finished:
112 | if(SUCCEEDED(hr))
113 | {
114 | _tprintf(L"\n Service '%s' started \n", pServiceName);
115 | }
116 | else
117 | {
118 | _tprintf(L"\nERROR: Failed to start or query status of service '%s' error [%x]\n", pServiceName, hr);
119 | }
120 |
121 | if (hService != NULL)
122 | {
123 | CloseServiceHandle(hService);
124 | }
125 | return hr;
126 | }
127 |
128 | HRESULT Service_Monitor::StopServiceByName(LPCTSTR pServiceName, DWORD dwTimeOutSeconds)
129 | {
130 | HRESULT hr = S_OK;
131 | SC_HANDLE hService = NULL;
132 | DWORD dwBytes = 0;
133 | DWORD dwSleepTime = 0;
134 | DWORD dwRemainTime = dwTimeOutSeconds;
135 | SERVICE_STATUS_PROCESS sStatus;
136 |
137 | hr = GetServiceHandle(pServiceName, &hService);
138 | if (SUCCEEDED(hr))
139 | {
140 | while (dwRemainTime >0)
141 | {
142 | DWORD dwBytes = 0;
143 | if (!QueryServiceStatusEx(hService,
144 | SC_STATUS_PROCESS_INFO,
145 | (LPBYTE)&sStatus,
146 | sizeof(SERVICE_STATUS_PROCESS),
147 | &dwBytes))
148 | {
149 | hr = HRESULT_FROM_WIN32(GetLastError());
150 | goto Finished;
151 | }
152 | if (sStatus.dwCurrentState == SERVICE_STOPPED)
153 | {
154 | goto Finished;
155 | }
156 | else if (sStatus.dwCurrentState == SERVICE_STOP_PENDING || sStatus.dwCurrentState == SERVICE_START_PENDING || sStatus.dwCurrentState == SERVICE_PAUSE_PENDING || sStatus.dwCurrentState == SERVICE_CONTINUE_PENDING)
157 | {
158 | dwSleepTime = rand() % 10 + 1;
159 | dwSleepTime = dwSleepTime < dwRemainTime ? dwSleepTime : dwRemainTime;
160 | dwRemainTime -= dwSleepTime;
161 | Sleep(dwSleepTime * 1000);
162 | }
163 | else if (sStatus.dwCurrentState == SERVICE_RUNNING || sStatus.dwCurrentState == SERVICE_PAUSED)
164 | {
165 | if (!ControlService(hService, SERVICE_CONTROL_STOP, (LPSERVICE_STATUS)&sStatus))
166 | {
167 | hr = HRESULT_FROM_WIN32(GetLastError());
168 | goto Finished;
169 | }
170 | _tprintf(L"\nStopping service '%s'\n", pServiceName);
171 | }
172 | else
173 | {
174 | //
175 | // Service fails to stop
176 | //
177 | hr = E_FAIL;
178 | goto Finished;
179 | }
180 | }
181 | //
182 | // cannot stop service within given time period
183 | //
184 | hr = HRESULT_FROM_WIN32(ERROR_TIMEOUT);
185 |
186 | }
187 |
188 | Finished:
189 | if (SUCCEEDED(hr))
190 | {
191 | _tprintf(L"\n Service '%s' has been stopped \n", pServiceName);
192 | }
193 | else
194 | {
195 | _tprintf(L"\nERROR: Failed to stop or query status of service '%s' error [%x]\n", pServiceName, hr);
196 | }
197 |
198 | if (hService != NULL)
199 | {
200 | CloseServiceHandle(hService);
201 | }
202 | return hr;
203 | }
204 |
205 | HRESULT Service_Monitor::MonitoringService(LPCTSTR pServiceName, DWORD dwStatus, HANDLE hStopEvent)
206 | {
207 | HRESULT hr = S_OK;
208 | DWORD dwError = ERROR_SUCCESS;
209 | DWORD dwWaitResult;
210 | SC_HANDLE hService;
211 | SERVICE_NOTIFY sNotify;
212 |
213 | hr = GetServiceHandle(pServiceName, &hService);
214 | if(FAILED(hr))
215 | {
216 | goto Finished;
217 | }
218 |
219 | sNotify.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE;
220 | sNotify.pfnNotifyCallback = (PFN_SC_NOTIFY_CALLBACK)NotifyCallBack;
221 | sNotify.pszServiceNames = (LPWSTR) pServiceName;
222 | sNotify.pContext = hStopEvent;
223 |
224 | dwError = NotifyServiceStatusChange(hService, dwStatus, &sNotify);
225 | if (dwError != ERROR_SUCCESS)
226 | {
227 | hr = HRESULT_FROM_WIN32(dwError);
228 | _tprintf(L"\nERROR: fail to register status change callback [%x]\n", hr);
229 | goto Finished;
230 | }
231 |
232 | dwWaitResult = WaitForSingleObjectEx(hStopEvent, INFINITE, TRUE);
233 | switch (dwWaitResult)
234 | {
235 | // Event object was signaled
236 | case WAIT_OBJECT_0:
237 | case WAIT_IO_COMPLETION:
238 | break;
239 |
240 | // An error occurred
241 | default:
242 | hr = HRESULT_FROM_WIN32(GetLastError());
243 | _tprintf(L"\nERROR: Monitoring service '%s' wait error [%x]\n", pServiceName, hr);
244 | }
245 |
246 | Finished:
247 | if (hService != NULL)
248 | {
249 | CloseServiceHandle(hService);
250 | }
251 | return hr;
252 | }
253 |
254 | HRESULT Service_Monitor::GetServiceHandle(LPCTSTR pServiceName, SC_HANDLE* pHandle)
255 | {
256 | HRESULT hr = S_OK;
257 |
258 | if (pServiceName == NULL)
259 | {
260 | _tprintf(L"\nERROR: Null parameter for GetServiceHandle()\n");
261 | hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
262 | goto Finished;
263 | }
264 |
265 | hr = EnsureInitialized();
266 | if (SUCCEEDED(hr))
267 | {
268 | *pHandle = OpenService(_hSCManager, pServiceName, SERVICE_START | SERVICE_STOP | SERVICE_QUERY_STATUS);
269 | if (*pHandle == NULL)
270 | {
271 | hr = HRESULT_FROM_WIN32(GetLastError());
272 | goto Finished;
273 | }
274 | }
275 |
276 | Finished:
277 | return hr;
278 | }
279 |
--------------------------------------------------------------------------------
/src/ServiceMonitor/ServiceMonitor.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license.
3 |
4 | #pragma once
5 |
6 | #include
7 |
8 | class Service_Monitor
9 | {
10 |
11 | public:
12 | Service_Monitor() :_hSCManager(NULL)
13 | {
14 | InitializeSRWLock(&_srwLock);
15 | }
16 |
17 | ~Service_Monitor()
18 | {
19 | if (_hSCManager != NULL)
20 | {
21 | CloseServiceHandle(_hSCManager);
22 | }
23 | }
24 |
25 | HRESULT EnsureInitialized();
26 | HRESULT StartServiceByName(LPCTSTR pServiceName, DWORD dwTimeOutSeconds = 20);
27 | HRESULT StopServiceByName(LPCTSTR pServiceName, DWORD dwTimeOutSeconds = 20);
28 | HRESULT MonitoringService(LPCTSTR pServiceName, DWORD dwStatus, HANDLE hStopEvent);
29 | static VOID CALLBACK NotifyCallBack(PVOID parameter);
30 |
31 | private:
32 | HRESULT GetServiceHandle(LPCTSTR pServiceName, SC_HANDLE* pHandle);
33 | SC_HANDLE _hSCManager;
34 | BOOL _fInitialized;
35 | SRWLOCK _srwLock;
36 | };
37 |
--------------------------------------------------------------------------------
/src/ServiceMonitor/ServiceMonitor.rc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/IIS.ServiceMonitor/1c4153056fd8ad8e61317af115153180dc10c2cc/src/ServiceMonitor/ServiceMonitor.rc
--------------------------------------------------------------------------------
/src/ServiceMonitor/ServiceMonitor.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Debug
7 | Win32
8 |
9 |
10 | Release
11 | Win32
12 |
13 |
14 | Debug
15 | x64
16 |
17 |
18 | Release
19 | x64
20 |
21 |
22 |
23 | {EFAE236B-EFB4-413C-8EEE-09F211558AC1}
24 | Win32Proj
25 | ServiceMonitor
26 | 10.0
27 |
28 |
29 |
30 | $(RepositoryRoot)bin\$(Configuration)\$(PlatformShortname)\
31 | $(RepositoryRoot)obj\$(PlatformShortname)\$(Configuration)\$(MSBuildThisFileName)\
32 |
33 |
34 | Application
35 | true
36 | v143
37 | Unicode
38 |
39 |
40 | Application
41 | false
42 | v143
43 | true
44 | Unicode
45 |
46 |
47 | Application
48 | true
49 | v143
50 | Unicode
51 |
52 |
53 | Application
54 | false
55 | v143
56 | true
57 | Unicode
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | true
79 |
80 |
81 | true
82 |
83 |
84 | false
85 |
86 |
87 | false
88 |
89 |
90 |
91 | Use
92 | Level3
93 | Disabled
94 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
95 | true
96 | MultiThreaded
97 |
98 |
99 | Console
100 | true
101 |
102 |
103 |
104 |
105 | Use
106 | Level3
107 | Disabled
108 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
109 | true
110 | MultiThreaded
111 |
112 |
113 | Console
114 | true
115 |
116 |
117 |
118 |
119 | Level3
120 | Use
121 | MaxSpeed
122 | true
123 | true
124 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
125 | true
126 | MultiThreaded
127 |
128 |
129 | Console
130 | true
131 | true
132 | true
133 |
134 |
135 |
136 |
137 | Level3
138 | Use
139 | MaxSpeed
140 | true
141 | true
142 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
143 | true
144 | MultiThreaded
145 |
146 |
147 | Console
148 | true
149 | true
150 | true
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 | Create
165 | Create
166 | Create
167 | Create
168 |
169 |
170 |
171 |
172 | SM_BUILDMINORVERSION=$(BUILD_MINOR)
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 | $(SigningIdentity)
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
190 |
191 |
192 |
193 |
194 |
--------------------------------------------------------------------------------
/src/ServiceMonitor/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/ServiceMonitor/stdafx.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license.
3 |
4 | // stdafx.cpp : source file that includes just the standard includes
5 | // ServiceMonitor.pch will be the pre-compiled header
6 | // stdafx.obj will contain the pre-compiled type information
7 |
8 | #include "stdafx.h"
9 |
10 | // TODO: reference any additional headers you need in STDAFX.H
11 | // and not in this file
12 |
--------------------------------------------------------------------------------
/src/ServiceMonitor/stdafx.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license.
3 |
4 | // stdafx.h : include file for standard system include files,
5 | // or project specific include files that are used frequently, but
6 | // are changed infrequently
7 | //
8 |
9 | #pragma once
10 |
11 | #include "targetver.h"
12 |
13 | #include
14 | #include
15 | #include
16 | #include "ServiceMonitor.h"
17 | #include "IISConfigUtil.h"
18 | #include
19 | #include
20 |
21 |
22 |
23 | // TODO: reference additional headers your program requires here
24 |
--------------------------------------------------------------------------------
/src/ServiceMonitor/targetver.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft Corporation. All rights reserved.
2 | // Licensed under the MIT license.
3 |
4 | #pragma once
5 |
6 | // Including SDKDDKVer.h defines the highest available Windows platform.
7 |
8 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
9 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
10 |
11 | #include
12 |
--------------------------------------------------------------------------------
/src/ServiceMonitor/version.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/IIS.ServiceMonitor/1c4153056fd8ad8e61317af115153180dc10c2cc/src/ServiceMonitor/version.h
--------------------------------------------------------------------------------