SHOW:
|
|
- or go back to the newest paste.
| 1 | <# | |
| 2 | .Synopsis | |
| 3 | Starts powershell webserver | |
| 4 | .Description | |
| 5 | Starts webserver as powershell process. | |
| 6 | Call of the root page (e.g. http://localhost:8080/) returns a powershell execution web form. | |
| 7 | Call of /script uploads a powershell script and executes it (as a function). | |
| 8 | Call of /log returns the webserver logs, /starttime the start time of the webserver, /time the current time. | |
| 9 | /download downloads and /upload uploads a file. /beep generates a sound and /quit or /exit stops the webserver. | |
| 10 | ||
| 11 | You may have to configure a firewall exception to allow access to the chosen port, e.g. with: | |
| 12 | netsh advfirewall firewall add rule name="Powershell Webserver" dir=in action=allow protocol=TCP localport=8080 | |
| 13 | ||
| 14 | After stopping the webserver you should remove the rule, e.g.: | |
| 15 | netsh advfirewall firewall delete rule name="Powershell Webserver" | |
| 16 | .Parameter BINDING | |
| 17 | Binding of the webserver | |
| 18 | .Inputs | |
| 19 | None | |
| 20 | .Outputs | |
| 21 | None | |
| 22 | .Example | |
| 23 | Start-Webserver.ps1 | |
| 24 | ||
| 25 | Starts webserver with binding to http://localhost:8080/ | |
| 26 | .Example | |
| 27 | Start-Webserver.ps1 "http://+:8080/" | |
| 28 | ||
| 29 | Starts webserver with binding to all IP addresses of the system. | |
| 30 | Administrative rights are necessary. | |
| 31 | .Example | |
| 32 | schtasks.exe /Create /TN "Powershell Webserver" /TR "powershell -file C:\Users\Markus\Documents\Start-WebServer.ps1 http://+:8080/" /SC ONSTART /RU SYSTEM /RL HIGHEST /F | |
| 33 | ||
| 34 | Starts powershell webserver as scheduled task as user local system every time the computer starts (when the | |
| 35 | correct path to the file Start-WebServer.ps1 is given). | |
| 36 | You can start the webserver task manually with | |
| 37 | schtasks.exe /Run /TN "Powershell Webserver" | |
| 38 | Delete the webserver task with | |
| 39 | schtasks.exe /Delete /TN "Powershell Webserver" | |
| 40 | Scheduled tasks are always running with low priority, so some functions might be slow. | |
| 41 | .Notes | |
| 42 | Author: Markus Scholtes, 2016-10-22 | |
| 43 | #> | |
| 44 | Param([STRING]$BINDING = 'http://localhost:8080/') | |
| 45 | ||
| 46 | # No adminstrative permissions are required for a binding to "localhost" | |
| 47 | # $BINDING = 'http://localhost:8080/' | |
| 48 | # Adminstrative permissions are required for a binding to network names or addresses. | |
| 49 | # + takes all requests to the port regardless of name or ip, * only requests that no other listener answers: | |
| 50 | # $BINDING = 'http://+:8080/' | |
| 51 | ||
| 52 | # HTML answer templates for specific calls, placeholders !RESULT, !FORMFIELD, !PROMPT are allowed | |
| 53 | $HTMLRESPONSECONTENTS = @{
| |
| 54 | 'GET /' = @" | |
| 55 | <html><body> | |
| 56 | !HEADERLINE | |
| 57 | <pre>!RESULT</pre> | |
| 58 | <form method="GET" action="/"> | |
| 59 | <b>!PROMPT </b><input type="text" maxlength=255 size=80 name="command" value='!FORMFIELD'> | |
| 60 | <input type="submit" name="button" value="Enter"> | |
| 61 | </form> | |
| 62 | </body></html> | |
| 63 | "@ | |
| 64 | 'GET /script' = @" | |
| 65 | <html><body> | |
| 66 | !HEADERLINE | |
| 67 | <form method="POST" enctype="multipart/form-data" action="/script"> | |
| 68 | <p><b>Script to execute:</b><input type="file" name="filedata"></p> | |
| 69 | <b>Parameters:</b><input type="text" maxlength=255 size=80 name="parameter"> | |
| 70 | <input type="submit" name="button" value="Execute"> | |
| 71 | </form> | |
| 72 | </body></html> | |
| 73 | "@ | |
| 74 | 'GET /download' = @" | |
| 75 | <html><body> | |
| 76 | !HEADERLINE | |
| 77 | <pre>!RESULT</pre> | |
| 78 | <form method="POST" action="/download"> | |
| 79 | <b>Path to file:</b><input type="text" maxlength=255 size=80 name="filepath" value='!FORMFIELD'> | |
| 80 | <input type="submit" name="button" value="Download"> | |
| 81 | </form> | |
| 82 | </body></html> | |
| 83 | "@ | |
| 84 | 'POST /download' = @" | |
| 85 | <html><body> | |
| 86 | !HEADERLINE | |
| 87 | <pre>!RESULT</pre> | |
| 88 | <form method="POST" action="/download"> | |
| 89 | <b>Path to file:</b><input type="text" maxlength=255 size=80 name="filepath" value='!FORMFIELD'> | |
| 90 | <input type="submit" name="button" value="Download"> | |
| 91 | </form> | |
| 92 | </body></html> | |
| 93 | "@ | |
| 94 | 'GET /upload' = @" | |
| 95 | <html><body> | |
| 96 | !HEADERLINE | |
| 97 | <form method="POST" enctype="multipart/form-data" action="/upload"> | |
| 98 | <p><b>File to upload:</b><input type="file" name="filedata"></p> | |
| 99 | <b>Path to store on webserver:</b><input type="text" maxlength=255 size=80 name="filepath"> | |
| 100 | <input type="submit" name="button" value="Upload"> | |
| 101 | </form> | |
| 102 | </body></html> | |
| 103 | "@ | |
| 104 | 'POST /script' = "<html><body>!HEADERLINE<pre>!RESULT</pre></body></html>" | |
| 105 | 'POST /upload' = "<html><body>!HEADERLINE<pre>!RESULT</pre></body></html>" | |
| 106 | 'GET /exit' = "<html><body>Stopped powershell webserver</body></html>" | |
| 107 | 'GET /quit' = "<html><body>Stopped powershell webserver</body></html>" | |
| 108 | 'GET /log' = "<html><body>!HEADERLINELog of powershell webserver:<br /><pre>!RESULT</pre></body></html>" | |
| 109 | 'GET /starttime' = "<html><body>!HEADERLINEPowershell webserver started at $(Get-Date -Format s)</body></html>" | |
| 110 | 'GET /time' = "<html><body>!HEADERLINECurrent time: !RESULT</body></html>" | |
| 111 | 'GET /beep' = "<html><body>!HEADERLINEBEEP...</body></html>" | |
| 112 | } | |
| 113 | ||
| 114 | # Set navigation header line for all web pages | |
| 115 | $HEADERLINE = "<p><a href='/'>Command execution</a> <a href='/script'>Execute script</a> <a href='/download'>Download file</a> <a href='/upload'>Upload file</a> <a href='/log'>Web logs</a> <a href='/starttime'>Webserver start time</a> <a href='/time'>Current time</a> <a href='/beep'>Beep</a> <a href='/quit'>Stop webserver</a></p>" | |
| 116 | ||
| 117 | # Starting the powershell webserver | |
| 118 | "$(Get-Date -Format s) Starting powershell webserver..." | |
| 119 | $LISTENER = New-Object System.Net.HttpListener | |
| 120 | $LISTENER.Prefixes.Add($BINDING) | |
| 121 | $LISTENER.Start() | |
| 122 | $Error.Clear() | |
| 123 | ||
| 124 | try | |
| 125 | {
| |
| 126 | "$(Get-Date -Format s) Powershell webserver started." | |
| 127 | $WEBLOG = "$(Get-Date -Format s) Powershell webserver started.`n" | |
| 128 | while ($LISTENER.IsListening) | |
| 129 | {
| |
| 130 | # analyze incoming request | |
| 131 | $CONTEXT = $LISTENER.GetContext() | |
| 132 | $REQUEST = $CONTEXT.Request | |
| 133 | $RESPONSE = $CONTEXT.Response | |
| 134 | $RESPONSEWRITTEN = $FALSE | |
| 135 | ||
| 136 | # log to console | |
| 137 | "$(Get-Date -Format s) $($REQUEST.RemoteEndPoint.Address.ToString()) $($REQUEST.httpMethod) $($REQUEST.Url.PathAndQuery)" | |
| 138 | # and in log variable | |
| 139 | $WEBLOG += "$(Get-Date -Format s) $($REQUEST.RemoteEndPoint.Address.ToString()) $($REQUEST.httpMethod) $($REQUEST.Url.PathAndQuery)`n" | |
| 140 | ||
| 141 | # is there a fixed coding for the request? | |
| 142 | $RECEIVED = '{0} {1}' -f $REQUEST.httpMethod, $REQUEST.Url.LocalPath
| |
| 143 | $HTMLRESPONSE = $HTMLRESPONSECONTENTS[$RECEIVED] | |
| 144 | $RESULT = '' | |
| 145 | ||
| 146 | # check for known commands | |
| 147 | switch ($RECEIVED) | |
| 148 | {
| |
| 149 | "GET /" | |
| 150 | { # execute command
| |
| 151 | # retrieve GET query string | |
| 152 | $FORMFIELD = '' | |
| 153 | $FORMFIELD = [URI]::UnescapeDataString(($REQUEST.Url.Query -replace "\+"," ")) | |
| 154 | # remove fixed form fields out of query string | |
| 155 | $FORMFIELD = $FORMFIELD -replace "\?command=","" -replace "\?button=enter","" -replace "&command=","" -replace "&button=enter","" | |
| 156 | # when command is given... | |
| 157 | if (![STRING]::IsNullOrEmpty($FORMFIELD)) | |
| 158 | {
| |
| 159 | try {
| |
| 160 | # ... execute command | |
| 161 | $RESULT = Invoke-Expression -EA SilentlyContinue $FORMFIELD 2> $NULL | Out-String | |
| 162 | } | |
| 163 | catch {}
| |
| 164 | if ($Error.Count -gt 0) | |
| 165 | { # retrieve error message on error
| |
| 166 | $RESULT += "`nError while executing '$FORMFIELD'`n`n" | |
| 167 | $RESULT += $Error[0] | |
| 168 | $Error.Clear() | |
| 169 | } | |
| 170 | } | |
| 171 | # preset form value with command for the caller's convenience | |
| 172 | $HTMLRESPONSE = $HTMLRESPONSE -replace '!FORMFIELD', $FORMFIELD | |
| 173 | # insert powershell prompt to form | |
| 174 | $PROMPT = "PS $PWD>" | |
| 175 | $HTMLRESPONSE = $HTMLRESPONSE -replace '!PROMPT', $PROMPT | |
| 176 | break | |
| 177 | } | |
| 178 | ||
| 179 | "GET /script" | |
| 180 | { # present upload form, nothing to do here
| |
| 181 | break | |
| 182 | } | |
| 183 | ||
| 184 | "POST /script" | |
| 185 | { # upload and execute script
| |
| 186 | ||
| 187 | # only if there is body data in the request | |
| 188 | if ($REQUEST.HasEntityBody) | |
| 189 | {
| |
| 190 | # set default message to error message (since we just stop processing on error) | |
| 191 | $RESULT = "Received corrupt or incomplete form data" | |
| 192 | ||
| 193 | # check content type | |
| 194 | if ($REQUEST.ContentType) | |
| 195 | {
| |
| 196 | # retrieve boundary marker for header separation | |
| 197 | $BOUNDARY = $NULL | |
| 198 | if ($REQUEST.ContentType -match "boundary=(.*);") | |
| 199 | { $BOUNDARY = "--" + $MATCHES[1] }
| |
| 200 | else | |
| 201 | { # marker might be at the end of the line
| |
| 202 | if ($REQUEST.ContentType -match "boundary=(.*)$") | |
| 203 | { $BOUNDARY = "--" + $MATCHES[1] }
| |
| 204 | } | |
| 205 | ||
| 206 | if ($BOUNDARY) | |
| 207 | { # only if header separator was found
| |
| 208 | ||
| 209 | # read complete header (inkl. file data) into string | |
| 210 | $READER = New-Object System.IO.StreamReader($REQUEST.InputStream, $REQUEST.ContentEncoding) | |
| 211 | $DATA = $READER.ReadToEnd() | |
| 212 | $READER.Close() | |
| 213 | $REQUEST.InputStream.Close() | |
| 214 | ||
| 215 | $PARAMETERS = "" | |
| 216 | $SOURCENAME = "" | |
| 217 | ||
| 218 | # separate headers by boundary string | |
| 219 | $DATA -replace "$BOUNDARY--\r\n", "$BOUNDARY`r`n--" -split "$BOUNDARY\r\n" | % {
| |
| 220 | # omit leading empty header and end marker header | |
| 221 | if (($_ -ne "") -and ($_ -ne "--")) | |
| 222 | {
| |
| 223 | # only if well defined header (separation between meta data and data) | |
| 224 | if ($_.IndexOf("`r`n`r`n") -gt 0)
| |
| 225 | {
| |
| 226 | # header data before two CRs is meta data | |
| 227 | # first look for the file in header "filedata" | |
| 228 | if ($_.Substring(0, $_.IndexOf("`r`n`r`n")) -match "Content-Disposition: form-data; name=(.*);")
| |
| 229 | {
| |
| 230 | $HEADERNAME = $MATCHES[1] -replace '\"' | |
| 231 | # headername "filedata"? | |
| 232 | if ($HEADERNAME -eq "filedata") | |
| 233 | { # yes, look for source filename
| |
| 234 | if ($_.Substring(0, $_.IndexOf("`r`n`r`n")) -match "filename=(.*)")
| |
| 235 | { # source filename found
| |
| 236 | $SOURCENAME = $MATCHES[1] -replace "`r`n$" -replace "`r$" -replace '\"' | |
| 237 | # store content of file in variable | |
| 238 | $FILEDATA = $_.Substring($_.IndexOf("`r`n`r`n") + 4) -replace "`r`n$"
| |
| 239 | } | |
| 240 | } | |
| 241 | } | |
| 242 | else | |
| 243 | { # look for other headers (we need "parameter")
| |
| 244 | if ($_.Substring(0, $_.IndexOf("`r`n`r`n")) -match "Content-Disposition: form-data; name=(.*)")
| |
| 245 | { # header found
| |
| 246 | $HEADERNAME = $MATCHES[1] -replace '\"' | |
| 247 | # headername "parameter"? | |
| 248 | if ($HEADERNAME -eq "parameter") | |
| 249 | { # yes, look for paramaters
| |
| 250 | $PARAMETERS = $_.Substring($_.IndexOf("`r`n`r`n") + 4) -replace "`r`n$" -replace "`r$"
| |
| 251 | } | |
| 252 | } | |
| 253 | } | |
| 254 | } | |
| 255 | } | |
| 256 | } | |
| 257 | ||
| 258 | if ($SOURCENAME -ne "") | |
| 259 | { # execute only if a source file exists
| |
| 260 | ||
| 261 | $EXECUTE = "function Powershell-WebServer-Func {`n" + $FILEDATA + "`n}`nPowershell-WebServer-Func " + $PARAMETERS
| |
| 262 | try {
| |
| 263 | # ... execute script | |
| 264 | $RESULT = Invoke-Expression -EA SilentlyContinue $EXECUTE 2> $NULL | Out-String | |
| 265 | } | |
| 266 | catch {}
| |
| 267 | if ($Error.Count -gt 0) | |
| 268 | { # retrieve error message on error
| |
| 269 | $RESULT += "`nError while executing script $SOURCENAME`n`n" | |
| 270 | $RESULT += $Error[0] | |
| 271 | $Error.Clear() | |
| 272 | } | |
| 273 | } | |
| 274 | else | |
| 275 | {
| |
| 276 | $RESULT = "No file data received" | |
| 277 | } | |
| 278 | } | |
| 279 | } | |
| 280 | } | |
| 281 | else | |
| 282 | {
| |
| 283 | $RESULT = "No client data received" | |
| 284 | } | |
| 285 | break | |
| 286 | } | |
| 287 | ||
| 288 | { $_ -like "* /download" } # GET or POST method are allowed for download page
| |
| 289 | { # download file
| |
| 290 | ||
| 291 | # is POST data in the request? | |
| 292 | if ($REQUEST.HasEntityBody) | |
| 293 | { # POST request
| |
| 294 | # read complete header into string | |
| 295 | $READER = New-Object System.IO.StreamReader($REQUEST.InputStream, $REQUEST.ContentEncoding) | |
| 296 | $DATA = $READER.ReadToEnd() | |
| 297 | $READER.Close() | |
| 298 | $REQUEST.InputStream.Close() | |
| 299 | ||
| 300 | # get headers into hash table | |
| 301 | $HEADER = @{}
| |
| 302 | $DATA.Split('&') | % { $HEADER.Add([URI]::UnescapeDataString(($_.Split('=')[0] -replace "\+"," ")), [URI]::UnescapeDataString(($_.Split('=')[1] -replace "\+"," "))) }
| |
| 303 | ||
| 304 | # read header 'filepath' | |
| 305 | $FORMFIELD = $HEADER.Item('filepath')
| |
| 306 | # remove leading and trailing double quotes since Test-Path does not like them | |
| 307 | $FORMFIELD = $FORMFIELD -replace "^`"","" -replace "`"$","" | |
| 308 | } | |
| 309 | else | |
| 310 | { # GET request
| |
| 311 | ||
| 312 | # retrieve GET query string | |
| 313 | $FORMFIELD = '' | |
| 314 | $FORMFIELD = [URI]::UnescapeDataString(($REQUEST.Url.Query -replace "\+"," ")) | |
| 315 | # remove fixed form fields out of query string | |
| 316 | $FORMFIELD = $FORMFIELD -replace "\?filepath=","" -replace "\?button=download","" -replace "&filepath=","" -replace "&button=download","" | |
| 317 | # remove leading and trailing double quotes since Test-Path does not like them | |
| 318 | $FORMFIELD = $FORMFIELD -replace "^`"","" -replace "`"$","" | |
| 319 | } | |
| 320 | ||
| 321 | # when path is given... | |
| 322 | if (![STRING]::IsNullOrEmpty($FORMFIELD)) | |
| 323 | { # check if file exists
| |
| 324 | if (Test-Path $FORMFIELD -PathType Leaf) | |
| 325 | {
| |
| 326 | try {
| |
| 327 | # ... download file | |
| 328 | $BUFFER = [System.IO.File]::ReadAllBytes($FORMFIELD) | |
| 329 | $RESPONSE.ContentLength64 = $BUFFER.Length | |
| 330 | $RESPONSE.SendChunked = $FALSE | |
| 331 | $RESPONSE.ContentType = "application/octet-stream" | |
| 332 | $FILENAME = Split-Path -Leaf $FORMFIELD | |
| 333 | $RESPONSE.AddHeader("Content-disposition", "attachment; filename=$FILENAME")
| |
| 334 | $RESPONSE.OutputStream.Write($BUFFER, 0, $BUFFER.Length) | |
| 335 | # mark response as already given | |
| 336 | $RESPONSEWRITTEN = $TRUE | |
| 337 | } | |
| 338 | catch {}
| |
| 339 | if ($Error.Count -gt 0) | |
| 340 | { # retrieve error message on error
| |
| 341 | $RESULT += "`nError while downloading '$FORMFIELD'`n`n" | |
| 342 | $RESULT += $Error[0] | |
| 343 | $Error.Clear() | |
| 344 | } | |
| 345 | } | |
| 346 | else | |
| 347 | {
| |
| 348 | # ... file not found | |
| 349 | $RESULT = "File $FORMFIELD not found" | |
| 350 | } | |
| 351 | } | |
| 352 | # preset form value with file path for the caller's convenience | |
| 353 | $HTMLRESPONSE = $HTMLRESPONSE -replace '!FORMFIELD', $FORMFIELD | |
| 354 | break | |
| 355 | } | |
| 356 | ||
| 357 | "GET /upload" | |
| 358 | { # present upload form, nothing to do here
| |
| 359 | break | |
| 360 | } | |
| 361 | ||
| 362 | "POST /upload" | |
| 363 | { # upload file
| |
| 364 | ||
| 365 | # only if there is body data in the request | |
| 366 | if ($REQUEST.HasEntityBody) | |
| 367 | {
| |
| 368 | # set default message to error message (since we just stop processing on error) | |
| 369 | $RESULT = "Received corrupt or incomplete form data" | |
| 370 | ||
| 371 | # check content type | |
| 372 | if ($REQUEST.ContentType) | |
| 373 | {
| |
| 374 | # retrieve boundary marker for header separation | |
| 375 | $BOUNDARY = $NULL | |
| 376 | if ($REQUEST.ContentType -match "boundary=(.*);") | |
| 377 | { $BOUNDARY = "--" + $MATCHES[1] }
| |
| 378 | else | |
| 379 | { # marker might be at the end of the line
| |
| 380 | if ($REQUEST.ContentType -match "boundary=(.*)$") | |
| 381 | { $BOUNDARY = "--" + $MATCHES[1] }
| |
| 382 | } | |
| 383 | ||
| 384 | if ($BOUNDARY) | |
| 385 | { # only if header separator was found
| |
| 386 | ||
| 387 | # read complete header (inkl. file data) into string | |
| 388 | $READER = New-Object System.IO.StreamReader($REQUEST.InputStream, $REQUEST.ContentEncoding) | |
| 389 | $DATA = $READER.ReadToEnd() | |
| 390 | $READER.Close() | |
| 391 | $REQUEST.InputStream.Close() | |
| 392 | ||
| 393 | # variables for filenames | |
| 394 | $FILENAME = "" | |
| 395 | $SOURCENAME = "" | |
| 396 | ||
| 397 | # separate headers by boundary string | |
| 398 | $DATA -replace "$BOUNDARY--\r\n", "$BOUNDARY`r`n--" -split "$BOUNDARY\r\n" | % {
| |
| 399 | # omit leading empty header and end marker header | |
| 400 | if (($_ -ne "") -and ($_ -ne "--")) | |
| 401 | {
| |
| 402 | # only if well defined header (seperation between meta data and data) | |
| 403 | if ($_.IndexOf("`r`n`r`n") -gt 0)
| |
| 404 | {
| |
| 405 | # header data before two CRs is meta data | |
| 406 | # first look for the file in header "filedata" | |
| 407 | if ($_.Substring(0, $_.IndexOf("`r`n`r`n")) -match "Content-Disposition: form-data; name=(.*);")
| |
| 408 | {
| |
| 409 | $HEADERNAME = $MATCHES[1] -replace '\"' | |
| 410 | # headername "filedata"? | |
| 411 | if ($HEADERNAME -eq "filedata") | |
| 412 | { # yes, look for source filename
| |
| 413 | if ($_.Substring(0, $_.IndexOf("`r`n`r`n")) -match "filename=(.*)")
| |
| 414 | { # source filename found
| |
| 415 | $SOURCENAME = $MATCHES[1] -replace "`r`n$" -replace "`r$" -replace '\"' | |
| 416 | # store content of file in variable | |
| 417 | $FILEDATA = $_.Substring($_.IndexOf("`r`n`r`n") + 4) -replace "`r`n$"
| |
| 418 | } | |
| 419 | } | |
| 420 | } | |
| 421 | else | |
| 422 | { # look for other headers (we need "filepath" to know where to store the file)
| |
| 423 | if ($_.Substring(0, $_.IndexOf("`r`n`r`n")) -match "Content-Disposition: form-data; name=(.*)")
| |
| 424 | { # header found
| |
| 425 | $HEADERNAME = $MATCHES[1] -replace '\"' | |
| 426 | # headername "filepath"? | |
| 427 | if ($HEADERNAME -eq "filepath") | |
| 428 | { # yes, look for target filename
| |
| 429 | $FILENAME = $_.Substring($_.IndexOf("`r`n`r`n") + 4) -replace "`r`n$" -replace "`r$" -replace '\"'
| |
| 430 | } | |
| 431 | } | |
| 432 | } | |
| 433 | } | |
| 434 | } | |
| 435 | } | |
| 436 | ||
| 437 | if ($FILENAME -ne "") | |
| 438 | { # upload only if a targetname is given
| |
| 439 | if ($SOURCENAME -ne "") | |
| 440 | { # only upload if source file exists
| |
| 441 | ||
| 442 | # check or construct a valid filename to store | |
| 443 | $TARGETNAME = "" | |
| 444 | # if filename is a container name, add source filename to it | |
| 445 | if (Test-Path $FILENAME -PathType Container) | |
| 446 | {
| |
| 447 | $TARGETNAME = Join-Path $FILENAME -ChildPath $(Split-Path $SOURCENAME -Leaf) | |
| 448 | } else {
| |
| 449 | # try name in the header | |
| 450 | $TARGETNAME = $FILENAME | |
| 451 | } | |
| 452 | ||
| 453 | try {
| |
| 454 | # ... save file with the same encoding as received | |
| 455 | [IO.File]::WriteAllText($TARGETNAME, $FILEDATA, $REQUEST.ContentEncoding) | |
| 456 | } | |
| 457 | catch {}
| |
| 458 | if ($Error.Count -gt 0) | |
| 459 | { # retrieve error message on error
| |
| 460 | $RESULT += "`nError saving '$TARGETNAME'`n`n" | |
| 461 | $RESULT += $Error[0] | |
| 462 | $Error.Clear() | |
| 463 | } | |
| 464 | else | |
| 465 | { # success
| |
| 466 | $RESULT = "File $SOURCENAME successfully uploaded as $TARGETNAME" | |
| 467 | } | |
| 468 | } | |
| 469 | else | |
| 470 | {
| |
| 471 | $RESULT = "No file data received" | |
| 472 | } | |
| 473 | } | |
| 474 | else | |
| 475 | {
| |
| 476 | $RESULT = "Missing target file name" | |
| 477 | } | |
| 478 | } | |
| 479 | } | |
| 480 | } | |
| 481 | else | |
| 482 | {
| |
| 483 | $RESULT = "No client data received" | |
| 484 | } | |
| 485 | break | |
| 486 | } | |
| 487 | ||
| 488 | "GET /log" | |
| 489 | { # return the webserver log (stored in log variable)
| |
| 490 | $RESULT = $WEBLOG | |
| 491 | break | |
| 492 | } | |
| 493 | ||
| 494 | "GET /time" | |
| 495 | { # return current time
| |
| 496 | $RESULT = Get-Date -Format s | |
| 497 | break | |
| 498 | } | |
| 499 | ||
| 500 | "GET /starttime" | |
| 501 | { # return start time of the powershell webserver (already contained in $HTMLRESPONSE, nothing to do here)
| |
| 502 | break | |
| 503 | } | |
| 504 | ||
| 505 | "GET /beep" | |
| 506 | { # Beep
| |
| 507 | [CONSOLE]::beep(800, 300) # or "`a" or [char]7 | |
| 508 | break | |
| 509 | } | |
| 510 | ||
| 511 | "GET /quit" | |
| 512 | { # stop powershell webserver, nothing to do here
| |
| 513 | break | |
| 514 | } | |
| 515 | ||
| 516 | "GET /exit" | |
| 517 | { # stop powershell webserver, nothing to do here
| |
| 518 | break | |
| 519 | } | |
| 520 | ||
| 521 | default | |
| 522 | { # unknown command, return error
| |
| 523 | $RESPONSE.StatusCode = 404 | |
| 524 | $HTMLRESPONSE = '<html><body>Page not found</body></html>' | |
| 525 | } | |
| 526 | ||
| 527 | } | |
| 528 | ||
| 529 | # only send response if not already done | |
| 530 | if (!$RESPONSEWRITTEN) | |
| 531 | {
| |
| 532 | # insert header line string into HTML template | |
| 533 | $HTMLRESPONSE = $HTMLRESPONSE -replace '!HEADERLINE', $HEADERLINE | |
| 534 | ||
| 535 | # insert result string into HTML template | |
| 536 | $HTMLRESPONSE = $HTMLRESPONSE -replace '!RESULT', $RESULT | |
| 537 | ||
| 538 | # return HTML answer to caller | |
| 539 | $BUFFER = [Text.Encoding]::UTF8.GetBytes($HTMLRESPONSE) | |
| 540 | $RESPONSE.ContentLength64 = $BUFFER.Length | |
| 541 | $RESPONSE.OutputStream.Write($BUFFER, 0, $BUFFER.Length) | |
| 542 | } | |
| 543 | ||
| 544 | # and finish answer to client | |
| 545 | $RESPONSE.Close() | |
| 546 | ||
| 547 | # received command to stop webserver? | |
| 548 | if ($RECEIVED -eq 'GET /exit' -or $RECEIVED -eq 'GET /quit') | |
| 549 | { # then break out of while loop
| |
| 550 | "$(Get-Date -Format s) Stopping powershell webserver..." | |
| 551 | break; | |
| 552 | } | |
| 553 | } | |
| 554 | } | |
| 555 | finally | |
| 556 | {
| |
| 557 | # Stop powershell webserver | |
| 558 | $LISTENER.Stop() | |
| 559 | $LISTENER.Close() | |
| 560 | "$(Get-Date -Format s) Powershell webserver stopped." | |
| 561 | } |