· 5 years ago · Jun 28, 2020, 09:04 PM
1Param([STRING]$BINDING = 'http://localhost:8080/', [STRING]$BASEDIR = "")
2
3if ($BASEDIR -eq "")
4{ # current filesystem path as base path for static content
5 $BASEDIR = (Get-Location -PSProvider "FileSystem").ToString()
6}
7# convert to absolute path
8$BASEDIR = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($BASEDIR)
9
10# MIME hash table for static content
11$MIMEHASH = @{".avi"="video/x-msvideo"; ".crt"="application/x-x509-ca-cert"; ".css"="text/css"; ".der"="application/x
12-x509-ca-cert"; ".flv"="video/x-flv"; ".gif"="image/gif"; ".htm"="text/html"; ".html"="text/html"; ".ico"="image/x-ic
13on"; ".jar"="application/java-archive"; ".jardiff"="application/x-java-archive-diff"; ".jpeg"="image/jpeg"; ".jpg"="i
14mage/jpeg"; ".js"="application/x-javascript"; ".mov"="video/quicktime"; ".mp3"="audio/mpeg"; ".mp4"="video/mp4"; ".mp
15eg"="video/mpeg"; ".mpg"="video/mpeg"; ".pdf"="application/pdf"; ".pem"="application/x-x509-ca-cert"; ".pl"="applicat
16ion/x-perl"; ".png"="image/png"; ".rss"="text/xml"; ".shtml"="text/html"; ".txt"="text/plain"; ".war"="application/ja
17va-archive"; ".wmv"="video/x-ms-wmv"; ".xml"="text/xml"}
18
19# HTML answer templates for specific calls, placeholders !RESULT, !FORMFIELD, !PROMPT are allowed
20$HTMLRESPONSECONTENTS = @{
21 'GET /' = @"
22<!doctype html><html><body>
23 !HEADERLINE
24 <pre>!RESULT</pre>
25 <form method="GET" action="/">
26 <b>!PROMPT </b><input type="text" maxlength=255 size=80 name="command" value='!FORMFIELD'>
27 <input type="submit" name="button" value="Enter">
28 </form>
29</body></html>
30"@
31 'GET /script' = @"
32<!doctype html><html><body>
33 !HEADERLINE
34 <form method="POST" enctype="multipart/form-data" action="/script">
35 <p><b>Script to execute:</b><input type="file" name="filedata"></p>
36 <b>Parameters:</b><input type="text" maxlength=255 size=80 name="parameter">
37 <input type="submit" name="button" value="Execute">
38 </form>
39</body></html>
40"@
41 'GET /download' = @"
42<!doctype html><html><body>
43 !HEADERLINE
44 <pre>!RESULT</pre>
45 <form method="POST" action="/download">
46 <b>Path to file:</b><input type="text" maxlength=255 size=80 name="filepath" value='!FORMFIELD'>
47 <input type="submit" name="button" value="Download">
48 </form>
49</body></html>
50"@
51 'POST /download' = @"
52<!doctype html><html><body>
53 !HEADERLINE
54 <pre>!RESULT</pre>
55 <form method="POST" action="/download">
56 <b>Path to file:</b><input type="text" maxlength=255 size=80 name="filepath" value='!FORMFIELD'>
57 <input type="submit" name="button" value="Download">
58 </form>
59</body></html>
60"@
61 'GET /upload' = @"
62<!doctype html><html><body>
63 !HEADERLINE
64 <form method="POST" enctype="multipart/form-data" action="/upload">
65 <p><b>File to upload:</b><input type="file" name="filedata"></p>
66 <b>Path to store on webserver:</b><input type="text" maxlength=255 size=80 name="filepath">
67 <input type="submit" name="button" value="Upload">
68 </form>
69</body></html>
70"@
71 'POST /script' = "<!doctype html><html><body>!HEADERLINE<pre>!RESULT</pre></body></html>"
72 'POST /upload' = "<!doctype html><html><body>!HEADERLINE<pre>!RESULT</pre></body></html>"
73 'GET /exit' = "<!doctype html><html><body>Stopped powershell webserver</body></html>"
74 'GET /quit' = "<!doctype html><html><body>Stopped powershell webserver</body></html>"
75 'GET /log' = "<!doctype html><html><body>!HEADERLINELog of powershell webserver:<br /><pre>!RESULT</pre></body></htm
76l>"
77 'GET /starttime' = "<!doctype html><html><body>!HEADERLINEPowershell webserver started at $(Get-Date -Format s)</bod
78y></html>"
79 'GET /time' = "<!doctype html><html><body>!HEADERLINECurrent time: !RESULT</body></html>"
80 'GET /beep' = "<!doctype html><html><body>!HEADERLINEBEEP...</body></html>"
81}
82
83# Set navigation header line for all web pages
84$HEADERLINE = "<p><a href='/'>Command execution</a> <a href='/script'>Execute script</a> <a href='/download'>Download
85 file</a> <a href='/upload'>Upload file</a> <a href='/log'>Web logs</a> <a href='/starttime'>Webserver start time</a>
86 <a href='/time'>Current time</a> <a href='/beep'>Beep</a> <a href='/quit'>Stop webserver</a></p>"
87
88# Starting the powershell webserver
89"$(Get-Date -Format s) Starting powershell webserver..."
90$LISTENER = New-Object System.Net.HttpListener
91$LISTENER.Prefixes.Add($BINDING)
92$LISTENER.Start()
93$Error.Clear()
94
95try
96{
97 "$(Get-Date -Format s) Powershell webserver started."
98 $WEBLOG = "$(Get-Date -Format s) Powershell webserver started.`n"
99 while ($LISTENER.IsListening)
100 {
101 # analyze incoming request
102 $CONTEXT = $LISTENER.GetContext()
103 $REQUEST = $CONTEXT.Request
104 $RESPONSE = $CONTEXT.Response
105 $RESPONSEWRITTEN = $FALSE
106
107 # log to console
108 "$(Get-Date -Format s) $($REQUEST.RemoteEndPoint.Address.ToString()) $($REQUEST.httpMethod) $($REQUEST.Url.PathAndQ
109uery)"
110 # and in log variable
111 $WEBLOG += "$(Get-Date -Format s) $($REQUEST.RemoteEndPoint.Address.ToString()) $($REQUEST.httpMethod) $($REQUEST.U
112rl.PathAndQuery)`n"
113
114 # is there a fixed coding for the request?
115 $RECEIVED = '{0} {1}' -f $REQUEST.httpMethod, $REQUEST.Url.LocalPath
116 $HTMLRESPONSE = $HTMLRESPONSECONTENTS[$RECEIVED]
117 $RESULT = ''
118
119 # check for known commands
120 switch ($RECEIVED)
121 {
122 "GET /"
123 { # execute command
124 # retrieve GET query string
125 $FORMFIELD = ''
126 $FORMFIELD = [URI]::UnescapeDataString(($REQUEST.Url.Query -replace "\+"," "))
127 # remove fixed form fields out of query string
128 $FORMFIELD = $FORMFIELD -replace "\?command=","" -replace "\?button=enter","" -replace "&command=","" -replace "&
129button=enter",""
130 # when command is given...
131 if (![STRING]::IsNullOrEmpty($FORMFIELD))
132 {
133 try {
134 # ... execute command
135 $RESULT = Invoke-Expression -EA SilentlyContinue $FORMFIELD 2> $NULL | Out-String
136 }
137 catch
138 {
139 # just ignore. Error handling comes afterwards since not every error throws an exception
140 }
141 if ($Error.Count -gt 0)
142 { # retrieve error message on error
143 $RESULT += "`nError while executing '$FORMFIELD'`n`n"
144 $RESULT += $Error[0]
145 $Error.Clear()
146 }
147 }
148 # preset form value with command for the caller's convenience
149 $HTMLRESPONSE = $HTMLRESPONSE -replace '!FORMFIELD', $FORMFIELD
150 # insert powershell prompt to form
151 $PROMPT = "PS $PWD>"
152 $HTMLRESPONSE = $HTMLRESPONSE -replace '!PROMPT', $PROMPT
153 break
154 }
155
156 "GET /script"
157 { # present upload form, nothing to do here
158 break
159 }
160
161 "POST /script"
162 { # upload and execute script
163
164 # only if there is body data in the request
165 if ($REQUEST.HasEntityBody)
166 {
167 # set default message to error message (since we just stop processing on error)
168 $RESULT = "Received corrupt or incomplete form data"
169
170 # check content type
171 if ($REQUEST.ContentType)
172 {
173 # retrieve boundary marker for header separation
174 $BOUNDARY = $NULL
175 if ($REQUEST.ContentType -match "boundary=(.*);")
176 { $BOUNDARY = "--" + $MATCHES[1] }
177 else
178 { # marker might be at the end of the line
179 if ($REQUEST.ContentType -match "boundary=(.*)$")
180 { $BOUNDARY = "--" + $MATCHES[1] }
181 }
182
183 if ($BOUNDARY)
184 { # only if header separator was found
185
186 # read complete header (inkl. file data) into string
187 $READER = New-Object System.IO.StreamReader($REQUEST.InputStream, $REQUEST.ContentEncoding)
188 $DATA = $READER.ReadToEnd()
189 $READER.Close()
190 $REQUEST.InputStream.Close()
191
192 $PARAMETERS = ""
193 $SOURCENAME = ""
194
195 # separate headers by boundary string
196 $DATA -replace "$BOUNDARY--\r\n", "$BOUNDARY`r`n--" -split "$BOUNDARY\r\n" | ForEach-Object {
197 # omit leading empty header and end marker header
198 if (($_ -ne "") -and ($_ -ne "--"))
199 {
200 # only if well defined header (separation between meta data and data)
201 if ($_.IndexOf("`r`n`r`n") -gt 0)
202 {
203 # header data before two CRs is meta data
204 # first look for the file in header "filedata"
205 if ($_.Substring(0, $_.IndexOf("`r`n`r`n")) -match "Content-Disposition: form-data; name=(.*);")
206 {
207 $HEADERNAME = $MATCHES[1] -replace '\"'
208 # headername "filedata"?
209 if ($HEADERNAME -eq "filedata")
210 { # yes, look for source filename
211 if ($_.Substring(0, $_.IndexOf("`r`n`r`n")) -match "filename=(.*)")
212 { # source filename found
213 $SOURCENAME = $MATCHES[1] -replace "`r`n$" -replace "`r$" -replace '\"'
214 # store content of file in variable
215 $FILEDATA = $_.Substring($_.IndexOf("`r`n`r`n") + 4) -replace "`r`n$"
216 }
217 }
218 }
219 else
220 { # look for other headers (we need "parameter")
221 if ($_.Substring(0, $_.IndexOf("`r`n`r`n")) -match "Content-Disposition: form-data; name=(.*)")
222 { # header found
223 $HEADERNAME = $MATCHES[1] -replace '\"'
224 # headername "parameter"?
225 if ($HEADERNAME -eq "parameter")
226 { # yes, look for paramaters
227 $PARAMETERS = $_.Substring($_.IndexOf("`r`n`r`n") + 4) -replace "`r`n$" -replace "`r$"
228 }
229 }
230 }
231 }
232 }
233 }
234
235 if ($SOURCENAME -ne "")
236 { # execute only if a source file exists
237
238 $EXECUTE = "function Powershell-WebServer-Func {`n" + $FILEDATA + "`n}`nPowershell-WebServer-Func " + $PARAME
239TERS
240 try {
241 # ... execute script
242 $RESULT = Invoke-Expression -EA SilentlyContinue $EXECUTE 2> $NULL | Out-String
243 }
244 catch
245 {
246 # just ignore. Error handling comes afterwards since not every error throws an exception
247 }
248 if ($Error.Count -gt 0)
249 { # retrieve error message on error
250 $RESULT += "`nError while executing script $SOURCENAME`n`n"
251 $RESULT += $Error[0]
252 $Error.Clear()
253 }
254 }
255 else
256 {
257 $RESULT = "No file data received"
258 }
259 }
260 }
261 }
262 else
263 {
264 $RESULT = "No client data received"
265 }
266 break
267 }
268
269 { $_ -like "* /download" } # GET or POST method are allowed for download page
270 { # download file
271
272 # is POST data in the request?
273 if ($REQUEST.HasEntityBody)
274 { # POST request
275 # read complete header into string
276 $READER = New-Object System.IO.StreamReader($REQUEST.InputStream, $REQUEST.ContentEncoding)
277 $DATA = $READER.ReadToEnd()
278 $READER.Close()
279 $REQUEST.InputStream.Close()
280
281 # get headers into hash table
282 $HEADER = @{}
283 $DATA.Split('&') | ForEach-Object { $HEADER.Add([URI]::UnescapeDataString(($_.Split('=')[0] -replace "\+"," ")),
284 [URI]::UnescapeDataString(($_.Split('=')[1] -replace "\+"," "))) }
285
286 # read header 'filepath'
287 $FORMFIELD = $HEADER.Item('filepath')
288 # remove leading and trailing double quotes since Test-Path does not like them
289 $FORMFIELD = $FORMFIELD -replace "^`"","" -replace "`"$",""
290 }
291 else
292 { # GET request
293
294 # retrieve GET query string
295 $FORMFIELD = ''
296 $FORMFIELD = [URI]::UnescapeDataString(($REQUEST.Url.Query -replace "\+"," "))
297 # remove fixed form fields out of query string
298 $FORMFIELD = $FORMFIELD -replace "\?filepath=","" -replace "\?button=download","" -replace "&filepath=","" -repl
299ace "&button=download",""
300 # remove leading and trailing double quotes since Test-Path does not like them
301 $FORMFIELD = $FORMFIELD -replace "^`"","" -replace "`"$",""
302 }
303
304 # when path is given...
305 if (![STRING]::IsNullOrEmpty($FORMFIELD))
306 { # check if file exists
307 if (Test-Path $FORMFIELD -PathType Leaf)
308 {
309 try {
310 # ... download file
311 $BUFFER = [System.IO.File]::ReadAllBytes($FORMFIELD)
312 $RESPONSE.ContentLength64 = $BUFFER.Length
313 $RESPONSE.SendChunked = $FALSE
314 $RESPONSE.ContentType = "application/octet-stream"
315 $FILENAME = Split-Path -Leaf $FORMFIELD
316 $RESPONSE.AddHeader("Content-Disposition", "attachment; filename=$FILENAME")
317 $RESPONSE.AddHeader("Last-Modified", [IO.File]::GetLastWriteTime($FORMFIELD).ToString('r'))
318 $RESPONSE.AddHeader("Server", "Powershell Webserver/1.2 on ")
319 $RESPONSE.OutputStream.Write($BUFFER, 0, $BUFFER.Length)
320 # mark response as already given
321 $RESPONSEWRITTEN = $TRUE
322 }
323 catch
324 {
325 # just ignore. Error handling comes afterwards since not every error throws an exception
326 }
327 if ($Error.Count -gt 0)
328 { # retrieve error message on error
329 $RESULT += "`nError while downloading '$FORMFIELD'`n`n"
330 $RESULT += $Error[0]
331 $Error.Clear()
332 }
333 }
334 else
335 {
336 # ... file not found
337 $RESULT = "File $FORMFIELD not found"
338 }
339 }
340 # preset form value with file path for the caller's convenience
341 $HTMLRESPONSE = $HTMLRESPONSE -replace '!FORMFIELD', $FORMFIELD
342 break
343 }
344
345 "GET /upload"
346 { # present upload form, nothing to do here
347 break
348 }
349
350 "POST /upload"
351 { # upload file
352
353 # only if there is body data in the request
354 if ($REQUEST.HasEntityBody)
355 {
356 # set default message to error message (since we just stop processing on error)
357 $RESULT = "Received corrupt or incomplete form data"
358
359 # check content type
360 if ($REQUEST.ContentType)
361 {
362 # retrieve boundary marker for header separation
363 $BOUNDARY = $NULL
364 if ($REQUEST.ContentType -match "boundary=(.*);")
365 { $BOUNDARY = "--" + $MATCHES[1] }
366 else
367 { # marker might be at the end of the line
368 if ($REQUEST.ContentType -match "boundary=(.*)$")
369 { $BOUNDARY = "--" + $MATCHES[1] }
370 }
371
372 if ($BOUNDARY)
373 { # only if header separator was found
374
375 # read complete header (inkl. file data) into string
376 $READER = New-Object System.IO.StreamReader($REQUEST.InputStream, $REQUEST.ContentEncoding)
377 $DATA = $READER.ReadToEnd()
378 $READER.Close()
379 $REQUEST.InputStream.Close()
380
381 # variables for filenames
382 $FILENAME = ""
383 $SOURCENAME = ""
384
385 # separate headers by boundary string
386 $DATA -replace "$BOUNDARY--\r\n", "$BOUNDARY`r`n--" -split "$BOUNDARY\r\n" | ForEach-Object {
387 # omit leading empty header and end marker header
388 if (($_ -ne "") -and ($_ -ne "--"))
389 {
390 # only if well defined header (seperation between meta data and data)
391 if ($_.IndexOf("`r`n`r`n") -gt 0)
392 {
393 # header data before two CRs is meta data
394 # first look for the file in header "filedata"
395 if ($_.Substring(0, $_.IndexOf("`r`n`r`n")) -match "Content-Disposition: form-data; name=(.*);")
396 {
397 $HEADERNAME = $MATCHES[1] -replace '\"'
398 # headername "filedata"?
399 if ($HEADERNAME -eq "filedata")
400 { # yes, look for source filename
401 if ($_.Substring(0, $_.IndexOf("`r`n`r`n")) -match "filename=(.*)")
402 { # source filename found
403 $SOURCENAME = $MATCHES[1] -replace "`r`n$" -replace "`r$" -replace '\"'
404 # store content of file in variable
405 $FILEDATA = $_.Substring($_.IndexOf("`r`n`r`n") + 4) -replace "`r`n$"
406 }
407 }
408 }
409 else
410 { # look for other headers (we need "filepath" to know where to store the file)
411 if ($_.Substring(0, $_.IndexOf("`r`n`r`n")) -match "Content-Disposition: form-data; name=(.*)")
412 { # header found
413 $HEADERNAME = $MATCHES[1] -replace '\"'
414 # headername "filepath"?
415 if ($HEADERNAME -eq "filepath")
416 { # yes, look for target filename
417 $FILENAME = $_.Substring($_.IndexOf("`r`n`r`n") + 4) -replace "`r`n$" -replace "`r$" -replace '\"'
418 }
419 }
420 }
421 }
422 }
423 }
424
425 if ($FILENAME -ne "")
426 { # upload only if a targetname is given
427 if ($SOURCENAME -ne "")
428 { # only upload if source file exists
429
430 # check or construct a valid filename to store
431 $TARGETNAME = ""
432 # if filename is a container name, add source filename to it
433 if (Test-Path $FILENAME -PathType Container)
434 {
435 $TARGETNAME = Join-Path $FILENAME -ChildPath $(Split-Path $SOURCENAME -Leaf)
436 } else {
437 # try name in the header
438 $TARGETNAME = $FILENAME
439 }
440
441 try {
442 # ... save file with the same encoding as received
443 [IO.File]::WriteAllText($TARGETNAME, $FILEDATA, $REQUEST.ContentEncoding)
444 }
445 catch
446 {
447 # just ignore. Error handling comes afterwards since not every error throws an exception
448 }
449 if ($Error.Count -gt 0)
450 { # retrieve error message on error
451 $RESULT += "`nError saving '$TARGETNAME'`n`n"
452 $RESULT += $Error[0]
453 $Error.Clear()
454 }
455 else
456 { # success
457 $RESULT = "File $SOURCENAME successfully uploaded as $TARGETNAME"
458 }
459 }
460 else
461 {
462 $RESULT = "No file data received"
463 }
464 }
465 else
466 {
467 $RESULT = "Missing target file name"
468 }
469 }
470 }
471 }
472 else
473 {
474 $RESULT = "No client data received"
475 }
476 break
477 }
478
479 "GET /log"
480 { # return the webserver log (stored in log variable)
481 $RESULT = $WEBLOG
482 break
483 }
484
485 "GET /time"
486 { # return current time
487 $RESULT = Get-Date -Format s
488 break
489 }
490
491 "GET /starttime"
492 { # return start time of the powershell webserver (already contained in $HTMLRESPONSE, nothing to do here)
493 break
494 }
495
496 "GET /beep"
497 { # Beep
498 [CONSOLE]::beep(800, 300) # or "`a" or [char]7
499 break
500 }
501
502 "GET /quit"
503 { # stop powershell webserver, nothing to do here
504 break
505 }
506
507 "GET /exit"
508 { # stop powershell webserver, nothing to do here
509 break
510 }
511
512 default
513 { # unknown command, check if path to file
514
515 # create physical path based upon the base dir and url
516 $CHECKDIR = $BASEDIR.TrimEnd("/\") + $REQUEST.Url.LocalPath
517 $CHECKFILE = ""
518 if (Test-Path $CHECKDIR -PathType Container)
519 { # physical path is a directory
520 $IDXLIST = "/index.htm", "/index.html", "/default.htm", "/default.html"
521 foreach ($IDXNAME in $IDXLIST)
522 { # check if an index file is present
523 $CHECKFILE = $CHECKDIR.TrimEnd("/\") + $IDXNAME
524 if (Test-Path $CHECKFILE -PathType Leaf)
525 { # index file found, path now in $CHECKFILE
526 break
527 }
528 $CHECKFILE = ""
529 }
530
531 if ($CHECKFILE -eq "")
532 { # generate directory listing
533 $HTMLRESPONSE = "<!doctype html><html><head><title>$($REQUEST.Url.LocalPath)</title><meta charset=""utf-8""></h
534ead><body><H1>$($REQUEST.Url.LocalPath)</H1><hr><pre>"
535 if ($REQUEST.Url.LocalPath -ne "" -And $REQUEST.Url.LocalPath -ne "/" -And $REQUEST.Url.LocalPath -ne "`\" -An
536d $REQUEST.Url.LocalPath -ne ".")
537 { # link to parent directory
538 $PARENTDIR = (Split-Path $REQUEST.Url.LocalPath -Parent) -replace '\\','/'
539 if ($PARENTDIR.IndexOf("/") -ne 0) { $PARENTDIR = "/" + $PARENTDIR }
540 $HTMLRESPONSE += "<pre><a href=""$PARENTDIR"">[To Parent Directory]</a><br><br>"
541 }
542
543 # read in directory listing
544 $ENTRIES = Get-ChildItem -EA SilentlyContinue -Path $CHECKDIR
545
546 # process directories
547 $ENTRIES | Where-Object { $_.PSIsContainer } | ForEach-Object { $HTMLRESPONSE += "$($_.LastWriteTime.ToString()
548) <dir> <a href=""$(Join-Path $REQUEST.Url.LocalPath $_.Name)"">$($_.Name)</a><br>" }
549
550 # process files
551 $ENTRIES | Where-Object { !$_.PSIsContainer } | ForEach-Object { $HTMLRESPONSE += "$($_.LastWriteTime.ToString(
552)) $("{0,10}" -f $_.Length) <a href=""$(Join-Path $REQUEST.Url.LocalPath $_.Name)"">$($_.Name)</a><br>" }
553
554 # end of directory listing
555 $HTMLRESPONSE += "</pre><hr></body></html>"
556 }
557 }
558 else
559 { # no directory, check for file
560 if (Test-Path $CHECKDIR -PathType Leaf)
561 { # file found, path now in $CHECKFILE
562 $CHECKFILE = $CHECKDIR
563 }
564 }
565
566 if ($CHECKFILE -ne "")
567 { # static content available
568 try {
569 # ... serve static content
570 $BUFFER = [System.IO.File]::ReadAllBytes($CHECKFILE)
571 $RESPONSE.ContentLength64 = $BUFFER.Length
572 $RESPONSE.SendChunked = $FALSE
573 $EXTENSION = [IO.Path]::GetExtension($CHECKFILE)
574 if ($MIMEHASH.ContainsKey($EXTENSION))
575 { # known mime type for this file's extension available
576 $RESPONSE.ContentType = $MIMEHASH.Item($EXTENSION)
577 }
578 else
579 { # no, serve as binary download
580 $RESPONSE.ContentType = "application/octet-stream"
581 $FILENAME = Split-Path -Leaf $CHECKFILE
582 $RESPONSE.AddHeader("Content-Disposition", "attachment; filename=$FILENAME")
583 }
584 $RESPONSE.AddHeader("Last-Modified", [IO.File]::GetLastWriteTime($CHECKFILE).ToString('r'))
585 $RESPONSE.AddHeader("Server", "Powershell Webserver/1.2 on ")
586 $RESPONSE.OutputStream.Write($BUFFER, 0, $BUFFER.Length)
587 # mark response as already given
588 $RESPONSEWRITTEN = $TRUE
589 }
590 catch
591 {
592 # just ignore. Error handling comes afterwards since not every error throws an exception
593 }
594 if ($Error.Count -gt 0)
595 { # retrieve error message on error
596 $RESULT += "`nError while downloading '$CHECKFILE'`n`n"
597 $RESULT += $Error[0]
598 $Error.Clear()
599 }
600 }
601 else
602 { # no file to serve found, return error
603 if (!(Test-Path $CHECKDIR -PathType Container))
604 {
605 $RESPONSE.StatusCode = 404
606 $HTMLRESPONSE = '<!doctype html><html><body>Diese Seite ist nicht vorhanden</body></html>'
607 }
608 }
609 }
610
611 }
612
613 # only send response if not already done
614 if (!$RESPONSEWRITTEN)
615 {
616 # insert header line string into HTML template
617 $HTMLRESPONSE = $HTMLRESPONSE -replace '!HEADERLINE', $HEADERLINE
618
619 # insert result string into HTML template
620 $HTMLRESPONSE = $HTMLRESPONSE -replace '!RESULT', $RESULT
621
622 # return HTML answer to caller
623 $BUFFER = [Text.Encoding]::UTF8.GetBytes($HTMLRESPONSE)
624 $RESPONSE.ContentLength64 = $BUFFER.Length
625 $RESPONSE.AddHeader("Last-Modified", [DATETIME]::Now.ToString('r'))
626 $RESPONSE.AddHeader("Server", "Powershell Webserver/1.2 on ")
627 $RESPONSE.OutputStream.Write($BUFFER, 0, $BUFFER.Length)
628 }
629
630 # and finish answer to client
631 $RESPONSE.Close()
632
633 # received command to stop webserver?
634 if ($RECEIVED -eq 'GET /exit' -or $RECEIVED -eq 'GET /quit')
635 { # then break out of while loop
636 "$(Get-Date -Format s) Stopping powershell webserver..."
637 break;
638 }
639 }
640}
641finally
642{
643 # Stop powershell webserver
644 $LISTENER.Stop()
645 $LISTENER.Close()
646 "$(Get-Date -Format s) Powershell webserver stopped."
647}