Skip to content

Instantly share code, notes, and snippets.

@russcam
Last active October 24, 2019 08:03
Show Gist options
  • Save russcam/7fbdbaa37e3dcb3fd3ee0aa54af3708c to your computer and use it in GitHub Desktop.
Save russcam/7fbdbaa37e3dcb3fd3ee0aa54af3708c to your computer and use it in GitHub Desktop.
PowerShell module to provide a curl like experience interacting with Elasticsearch from PowerShell
New-Module -Name ElasticShell -Scriptblock {
<#
.Synopsis
Execute REST API requests against Elasticsearch
.Description
Execute REST API requests against Elasticsearch.
Provides a curl-like experience for interacting with Elasticsearch, but with \m/ PowerShell \m/
.Example
es _cat/indices
.Example
es twitter/tweet/1 -Pretty -Method PUT -Body @'
{
"user" : "kimchy",
"post_date" : "2009-11-15T14:12:12",
"message" : "trying out Elasticsearch"
}
'@
.Example
es posts/_search?pretty -u elastic:changeme -d @{
query = @{
match = @{
user = "kimchy"
}
}
}
.Example
es posts/_bulk -ContentType application/x-ndjson -d C:\data.json
.Example
gc C:\data.json | es posts/_bulk -ContentType application/x-ndjson
.Parameter Method
the HTTP method to use. For requests with a body, will default to POST and without, GET.
.Parameter Uri
the Uri to request. A relative path will make a request to http://localhost:9200
.Parameter User
the username for Authentication. the password may also be specified here using the format username:password
.Parameter Password
the password for Authentication. if username is specified but password is not, a prompt will be displayed to provide the password.
.Parameter Body
the request body. May be a JSON string literal, a HashTable, or a path to a file containing JSON
.Parameter ContentType
the Content-Type HTTP header. By default, uses "application/json"
.Parameter Headers
the HTTP headers to send
.Parameter Pretty
Pretty print (indent) the JSON response. May be supplied as a query string parameter on Uri with ?pretty or ?pretty=true
.Parameter ResponseVariable
The name of a variable to which the response will be assigned, with global scope.
The response can be inspected for response headers, status code, etc.
.Inputs
the request body. May be a JSON string literal, a HashTable, or a path to a file containing JSON
.Outputs
the response body
.Notes
Author: Russ Cam - forloop.co.uk
License: Apache-2.0 - https://www.apache.org/licenses/LICENSE-2.0.txt
.Link
https://forloop.co.uk
.Link
https://www.elastic.co/products/elasticsearch
#>
function Invoke-Elasticsearch {
[CmdletBinding()]
[OutputType([String])]
param (
[string]
[ValidateSet("GET", "PUT", "POST", "DELETE", "HEAD")]
[Alias("X")]
$Method,
[string]
[Parameter(Mandatory=$true,Position=0)]
$Uri,
[string]
[Alias("u")]
$User,
[SecureString]
$Password,
[Alias("d")]
[Alias("data")]
[Parameter(ValueFromPipeline=$true)]
$Body,
[string]
$ContentType = "application/json",
[Alias("H")]
$Headers = @{},
[switch]
$Pretty,
[Alias("r")]
[Alias("response")]
[string]
$ResponseVariable
)
Begin {
Add-Type -AssemblyName System.Web
}
Process {
if (-not $Method) {
if ($Body) {
$Method = "Post"
} else {
$Method = "Get"
}
}
if ($Uri) {
$parsedUri = $null
if ([Uri]::TryCreate($Uri, [UriKind]::RelativeOrAbsolute, [ref]$parsedUri) -and `
-not $parsedUri.IsAbsoluteUri) {
$parsedUri = New-Object System.Uri "http://localhost:9200/$($parsedUri.OriginalString.TrimStart('/'))"
}
}
else {
$parsedUri = New-Object System.Uri "http://localhost:9200/"
}
# ParseQueryString does not respect keys without values, so test .Query directly
if ($Pretty -and (-not $parsedUri.Query -or $parsedUri.Query -match "[?|&]pretty(?=\=false)")) {
$queryString = [Web.HttpUtility]::ParseQueryString($parsedUri.Query)
if (-not $queryString) {
$queryString = New-Object System.Collections.Specialized.NameValueCollection
}
$queryString.Set("pretty","true")
$uriBuilder = New-Object System.UriBuilder $parsedUri
$uriBuilder.Query = $queryString.ToString();
$parsedUri = $uriBuilder.Uri
}
if ($User) {
$userParts = $User.Split(':', 2)
if ($userParts.Length -eq 2) {
$User = $userParts[0]
$Password = $userParts[1] | ConvertTo-SecureString -AsPlainText -Force
}
while (-not $Password -or $Password.Length -eq 0) {
$Password = Read-Host -AsSecureString "Enter password for $($User):"
}
$credential = New-Object System.Management.Automation.PSCredential ($User, $Password)
}
$requestParameters = @{
Uri = $parsedUri
ContentType = $ContentType
Headers = $Headers
Credential = $credential
Method = $Method
UseBasicParsing = $true
}
if ($Body -and $Body -is [string]) {
if (Test-Path $Body -PathType Leaf) {
$requestParameters.InFile = $Body
} else {
$requestParameters.Body = $Body
}
} else {
$requestParameters.Body = $Body = $Body | ConvertTo-Json
}
try {
$response = iwr @requestParameters
if ($ResponseVariable) {
Set-Variable -Name $ResponseVariable -Value $response -Scope Global
}
return $response.Content
}
catch {
$response = $_.Exception.Response
if ($ResponseVariable) {
Set-Variable -Name $ResponseVariable -Value $response -Scope Global
}
if ($response) {
$responseStream = $response.GetResponseStream()
$reader = New-Object System.IO.StreamReader($responseStream)
$reader.BaseStream.Position = 0
$reader.DiscardBufferedData()
return $reader.ReadToEnd()
} else {
throw $_.Exception
}
}
}
}
Set-Alias -Name es -Value Invoke-Elasticsearch -Description "Sends a request to Elasticsearch"
Set-Alias -Name hash -Value ConvertFrom-Json -Description "Converts JSON into a dictionary/hashmap"
Export-ModuleMember -Function 'Invoke-Elasticsearch' -Alias 'es','hash'
}
@russcam
Copy link
Author

russcam commented Feb 26, 2018

To install

. { iwr -useb https://gist.githubusercontent.com/russcam/7fbdbaa37e3dcb3fd3ee0aa54af3708c/raw/6143f8f509e466c65323c352ff07dd2cc81a6376/ElasticShell.ps1 } | iex;

@russcam
Copy link
Author

russcam commented Oct 24, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment