# Copyright (c) 2014 Microsoft Corp.
## Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
Function ConvertTo-HashTable {
<#
.Synopsis
Convert an object to a HashTable
.Description
Convert an object to a HashTable excluding certain types. For example, ListDictionaryInternal doesn't support serialization therefore
can't be converted to JSON.
.Parameter InputObject
Object to convert
.Parameter ExcludeTypeName
Array of types to skip adding to resulting HashTable. Default is to skip ListDictionaryInternal and Object arrays.
.Parameter MaxDepth
Maximum depth of embedded objects to convert. Default is 4.
.Example
$bios = get-ciminstance win32_bios
$bios | ConvertTo-HashTable
#>
Param (
[Parameter(Mandatory=$true,ValueFromPipeline=$true)]
[Object]$InputObject,
[string[]]$ExcludeTypeName = @("ListDictionaryInternal","Object[]"),
[ValidateRange(1,10)][Int]$MaxDepth = 4
)
Process {
Write-Verbose "Converting to hashtable $($InputObject.GetType())"
#$propNames = Get-Member -MemberType Properties -InputObject $InputObject | Select-Object -ExpandProperty Name
$propNames = $InputObject.psobject.Properties | Select-Object -ExpandProperty Name
$hash = @{}
$propNames | ForEach-Object {
if ($null -ne $InputObject.$_) {
if ($InputObject.$_ -is [string] -or (Get-Member -MemberType Properties -InputObject ($InputObject.$_) ).Count -eq 0) {
$hash.Add($_,$InputObject.$_)
} else {
if ($InputObject.$_.GetType().Name -in $ExcludeTypeName) {
Write-Verbose "Skipped $_"
} elseif ($MaxDepth -gt 1) {
$hash.Add($_,(ConvertTo-HashTable -InputObject $InputObject.$_ -MaxDepth ($MaxDepth - 1)))
}
}
}
}
$hash
}
}
Function Start-HTTPListener {
<#
.Synopsis
Creates a new HTTP Listener accepting PowerShell command line to execute
.Description
Creates a new HTTP Listener enabling a remote client to execute PowerShell command lines using a simple REST API.
This function requires running from an elevated administrator prompt to open a port.
Use Ctrl-C to stop the listener. You'll need to send another web request to allow the listener to stop since
it will be blocked waiting for a request.
.Parameter Port
Port to listen, default is 8888
.Parameter URL
URL to listen, default is /
.Parameter Auth
Authentication Schemes to use, default is IntegratedWindowsAuthentication
.Example
Start-HTTPListener -Port 8080 -Url PowerShell
Invoke-WebRequest -Uri "http://localhost:8888/PowerShell?command=get-service winmgmt&format=text" -UseDefaultCredentials | Format-List *
#>
Param (
[Parameter()]
[Int] $Port = 8888,
[Parameter()]
[String] $Url = "",
[Parameter()]
[System.Net.AuthenticationSchemes] $Auth = [System.Net.AuthenticationSchemes]::IntegratedWindowsAuthentication
)
Process {
$ErrorActionPreference = "Stop"
$CurrentPrincipal = New-Object Security.Principal.WindowsPrincipal( [Security.Principal.WindowsIdentity]::GetCurrent())
if ( -not ($currentPrincipal.IsInRole( [Security.Principal.WindowsBuiltInRole]::Administrator ))) {
Write-Error "This script must be executed from an elevated PowerShell session" -ErrorAction Stop
}
if ($Url.Length -gt 0 -and -not $Url.EndsWith('/')) {
$Url += "/"
}
$listener = New-Object System.Net.HttpListener
$prefix = "http://*:$Port/$Url"
$listener.Prefixes.Add($prefix)
$listener.AuthenticationSchemes = $Auth
try {
$listener.Start()
while ($true) {
$statusCode = 200
Write-Warning "Note that thread is blocked waiting for a request. After using Ctrl-C to stop listening, you need to send a valid HTTP request to stop the listener cleanly."
Write-Warning "Sending 'exit' command will cause listener to stop immediately"
Write-Verbose "Listening on $port..."
$context = $listener.GetContext()
$request = $context.Request
if (!$request.IsAuthenticated) {
Write-Warning "Rejected request as user was not authenticated"
$statusCode = 403
$commandOutput = "Unauthorized"
} else {
$identity = $context.User.Identity
Write-Verbose "Received request $(get-date) from $($identity.Name):"
$request | Format-List * | Out-String | Write-Verbose
# only allow requests that are the same identity as the one who started the listener
if ($identity.Name -ne $CurrentPrincipal.Identity.Name) {
Write-Warning "Rejected request as user doesn't match current security principal of listener"
$statusCode = 403
$commandOutput = "Unauthorized"
} else {
if (-not $request.QueryString.HasKeys()) {
$commandOutput = "SYNTAX: command=<string> format=[JSON|TEXT|XML|NONE|CLIXML]"
$Format = "TEXT"
} else {
$command = $request.QueryString.Item("command")
if ($command -eq "exit") {
Write-Verbose "Received command to exit listener"
return
}
$Format = $request.QueryString.Item("format")
if ($Null -eq $Format) {
$Format = "JSON"
}
Write-Verbose "Command = $command"
Write-Verbose "Format = $Format"
try {
$script = $ExecutionContext.InvokeCommand.NewScriptBlock($command)
$commandOutput = & $script
} catch {
$commandOutput = $_ | ConvertTo-HashTable
$statusCode = 500
}
}
$commandOutput = switch ($Format) {
TEXT { $commandOutput | Out-String ; break }
JSON { $commandOutput | ConvertTo-JSON; break }
XML { $commandOutput | ConvertTo-XML -As String; break }
CLIXML { [System.Management.Automation.PSSerializer]::Serialize($commandOutput) ; break }
default { "Invalid output format selected, valid choices are TEXT, JSON, XML, and CLIXML"; $statusCode = 501; break }
}
}
}
Write-Verbose "Response:"
if (!$commandOutput) {
$commandOutput = [string]::Empty
}
Write-Verbose $commandOutput
$response = $context.Response
$response.StatusCode = $statusCode
$buffer = [System.Text.Encoding]::UTF8.GetBytes($commandOutput)
$response.ContentLength64 = $buffer.Length
$output = $response.OutputStream
$output.Write($buffer,0,$buffer.Length)
$output.Close()
}
} finally {
$listener.Stop()
}
}
}
Источник: Тут
Комментариев нет:
Отправить комментарий