common.psm1
#requires -version 5 # to enable System.Web classes [System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") Add-Type -AssemblyName System.Web .(commonLib) Function GetXtremErrorMsg([AllowNull()][object]$errordata){ #return $errordata.ToString() $ed = $errordata if ($ed.ErrorDetails -ne $null) { return $ed.ErrorDetails } try{ $ed = $_.Exception.Response.GetResponseStream() $reader = New-Object System.IO.StreamReader($ed) $responseBody = $reader.ReadToEnd(); $errorcontent = $responseBody | ConvertFrom-Json $errormsg = $errorcontent.message if ($errormsg -eq $null) { $errorcontent = $errordata.Exception; } return $errorcontent } catch { Write-Host "" return $errordata.ToString() } } ######### REQUEST HELPERS ######### #Generates Header to be used in requests to XtremIO Function GetXtremAuthHeader([string]$username,[string]$password) { $basicAuth = ("{0}:{1}" -f $username,$password) $basicAuth = [System.Text.Encoding]::UTF8.GetBytes($basicAuth) $basicAuth = [System.Convert]::ToBase64String($basicAuth) $headers = @{Authorization=("Basic {0}" -f $basicAuth)} return $headers } Function GetXtremRawRequest{ [CmdletBinding()] Param( [Parameter()] [object]$Session = (Get-XtremDefaultSession), [Parameter(Mandatory=$true)] [String]$URI, [Parameter()] [switch]$ShowRest) $Username = $Session._XtremUsername $XmsName = $Session._XtremName $XtremClusterName = $Session._XtremDefaultCluster $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Session._XtremPassword) $Password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR) try { ##Construct Auth Header and full URI $Header = GetXtremAuthHeader -username $username -password $password $result = (Invoke-RestMethod -Method "POST" -Uri $Uri -Headers $Header) } catch { $err = GetXtremErrorMsg -errordata $_ throw $err } return $result } function showRestIfset(){ if ($ShowRest) { $show = "$($Method): $Uri" if ($Body -and $Body.length -gt 2){ $show += "`nBody: $Body" } Write-Host $show } } # Build the URL For a request. Function BuildURIRequest { Param( [String]$Endpoint, [Parameter()] [String]$XmsName, [Parameter()] $XtremClusterName, [Parameter()] [String[]]$Properties = $null, [Parameter()] [String]$GetProperty = $null, [Parameter()] [Array]$Filters = $null, [Parameter()] [switch]$Full = $false, [Parameter()] [switch]$Events = $false) $BaseUri = "https://$XmsName/api/json/v3" $PropertyString = '' $FilterString = '' $ClusterString = '' $v2UriExceptions = @( "/types/snapshots", "/types/consistency-group-volumes" ) if ($Endpoint -in $v2UriExceptions) { $BaseUri = $BaseUri -replace ("/v3$", "/v2") } if ($Events) { if ($Property.Count -ne 0) { $PropertyString += "prop-list=[" Foreach($Property in $Properties) { if($Property -eq $Properties[($Property.Length -1)]) { $PropertyString += $Property+"]" } else { $PropertyString += $Property+"," } } } } elseif($Property -and !$Full) { $propsArray = [System.Web.HttpUtility]::ParseQueryString('') #If properties were specified, builds a string for querying those Foreach($Property in $Properties) { $propsArray.Add( "prop", $Property ); } $PropertyString = $propsArray.ToString() } else { $PropertyString = $null } # Adding filters if($Filter) { Foreach($Filter in $Filters) { if($Filter -eq $Filters[($Filters.Length-1)]) { $FilterString += 'filter=' + $Filter } else { $FilterString += 'filter=' + $Filter + '&' } } } #If a cluster name was specified, builds a string for that if($XtremClusterName){ if($XtremClusterName -is [int]){ $nameFromTable = $global:XtremDefaultSessionObject._XtremClustersTable.$XtremClusterName if($nameFromTable){ $XtremClusterName = $nameFromTable }else{ $XtremClusterName = (Get-XtremCluster -Index $XtremClusterName).name } } $ClusterString = 'cluster-name='+$XtremClusterName if ($Endpoint -like "*remote-protections*"){ $ClusterString = 'cluster-id=' + $XtremClusterName } } else { $ClusterString = $null } # if($PropertyString -or $Full) { #another special case for performance calls... if($Endpoint -like "*performance*" -or $Endpoint -like "*event*") { $PropertyString = $PropertyString } else { $PropertyString = 'full=1&'+$PropertyString } # } #build URI $Uri = $baseUri + $Endpoint + '?' if ($GetProperty) { $Uri += $GetProperty + '&' } if ($ClusterString) { if ($Endpoint -notmatch 'user-accounts|r-snapshot-sets') { $Uri += $ClusterString + '&' } } if ($PropertyString) { $Uri += $PropertyString +'&' } if ($FilterString) { $Uri += $FilterString } #Check if we have left overs. if ($Uri.EndsWith('?') -or $Uri.EndsWith('&')) { $Uri = $Uri.Substring(0,$Uri.Length-1) } return $Uri; } Function XtremGETRequest ($Header, $Endpoint, $URI) { #special way of handling performance calls, special JSON serializer needs to be used as payload is large if($Endpoint -like "*performance*") { $jsonserial= New-Object -TypeName System.Web.Script.Serialization.JavaScriptSerializer $jsonserial.MaxJsonLength = [int]::MaxValue $data = $jsonserial.DeserializeObject((Invoke-WebRequest -Method $Method -Uri $Uri -Headers $Header -UseBasicParsing)) return $data } # $result = (Invoke-RestMethod -Method "GET" -Uri $Uri -Headers $Header ) $result = InvokeAsyncAnim { param($Uri, $Header, $Body) try { $res1 = (Invoke-RestMethod -Method "GET" -Uri $Uri -Headers $Header -ErrorAction Stop) } catch { $res1 = 'Error: ' if(!$_.Exception.Response){ $res1 += $_.Exception.Message }else{ $ed = $_.Exception.Response.GetResponseStream() $reader = New-Object System.IO.StreamReader($ed) $responseBody = $reader.ReadToEnd(); $errorcontent = $responseBody | ConvertFrom-Json $res1 += '' + $errorcontent.error_code + ' ' + $errorcontent.message; } } return $res1 } $result = findSelectedObject # Weird fix but it helps to formatOutput of single objects if ($result -and $result.getType().name -eq 'PSCustomObject'){ $result = $result | ConvertTo-Json | ConvertFrom-Json } return $result } function InvokeAsyncAnim ($code){ initAnimation # $rsPool = [runspacefactory]::CreateRunspacePool(1, 3) # $rsPool.Open() $PSinstance = [powershell]::Create().AddScript($code).AddArgument($Uri).AddArgument($Header).AddArgument($Body) # $PSinstance.RunspacePool = $rsPool $Handle = $PSinstance.BeginInvoke() for ($i = 0; $i -lt 99990; $i++) { if (!$Handle.IsCompleted) { doAnimation } else { $res = $PSinstance.EndInvoke($Handle) $PSinstance.Dispose() # $rsPool.Close() # $rsPool.Dispose() endAnimation return $res } } $PSinstance.Dispose() } $script:consoleName = $null function isConsoleHost{ if ($consoleName){ return ($consoleName -eq 'ConsoleHost') }else{ $script:consoleName = $host.Name return isConsoleHost } } function initAnimation { if (isConsoleHost) { [int]$script:l = [Console]::CursorLeft [int]$script:t = [Console]::CursorTop [Console]::CursorVisible = $false [int]$script:animSpan = 8 [int]$script:animCount = 0 [int]$script:animDir = 1 } } function endAnimation{ if (isConsoleHost) { clearAnimationText [Console]::CursorVisible = $true } } function clearAnimationText { if (isConsoleHost) { [Console]::CursorLeft = $l [Console]::CursorTop = $t Write-Host "$(' '*$animCount)" -NoNewline [Console]::CursorLeft = $l [Console]::CursorTop = $t } } function doAnimation { if (isConsoleHost) { clearAnimationText $script:animCount += $animDir Write-Host "$('.'*$animCount)" -NoNewline if ($animDir -eq 1 -and $animCount -ge $animSpan) { $script:animDir = -1 } if ($animDir -eq -1 -and $animCount -le 0) { $script:animDir = 1 } } Start-Sleep -Milliseconds 50 } function findSelectedObject{ if(!$result) {return ''} if ($ObjectSelection) { return $result.$ObjectSelection } else { if ($result.getType().name -eq 'String') { return $result } foreach ($property in $result.PSObject.Properties) { if (($property.name -ne 'params') -and ($property.name -ne 'links')) { $result = $property.value break } } return $result } } Function XtremPOSTRequest { Param( [Parameter(Mandatory=$true)] [Object]$Header, [Parameter(Mandatory=$true)] [String]$Uri, [Parameter()] [String]$Body) # $data = (Invoke-RestMethod -Method "POST" -Uri $Uri -Body $Body -Headers $Header) $data = InvokeAsyncAnim { param($Uri, $Header, $Body) try { $res1 = (Invoke-RestMethod -Method 'POST' -Uri $Uri -Headers $Header -Body $Body) } catch { $res1 = 'Error: ' if(!$_.Exception.Response){ $res1 += $_.Exception.Message }else{ $ed = $_.Exception.Response.GetResponseStream() $reader = New-Object System.IO.StreamReader($ed) $responseBody = $reader.ReadToEnd(); $errorcontent = $responseBody | ConvertFrom-Json $res1 += '' + $errorcontent.error_code + ' ' + $errorcontent.message; } } return $res1 } if(!$data.links){ return $data } $time = Get-Date $href = $data.links.href # Sometimes there are more than one object being created, so we'll return them all in an array if($href.count -gt 1) { $arr = @() for($i = 0; $i -lt $href.count; $i++) { # Resolve Each object $objectIndex = ($href[$i].Split('/')[-1]) $ResponseObject = new-object PSObject $ResponseObject | add-member -Type NoteProperty -Name Guid -Value ([int]$objectIndex) $ResponseObject | add-member -type NoteProperty -Name CreationTime -Value $time $arr += $ResponseObject } return $arr } else { $objectIndex = $href.Split('/')[-1] $ResponseObject = new-object PSObject if ($objectIndex.GetType().Name -eq "String") { $ResponseObject | add-member -type NoteProperty -Name Guid -Value ([String]$objectIndex) } else { $ResponseObject | add-member -type NoteProperty -Name Guid -Value ([int]$objectIndex) } $ResponseObject | add-member -type NoteProperty -Name CreationTime -Value $time return $ResponseObject } } Function XtremPUTRequest { Param( [Parameter(Mandatory=$true)] [Object]$Header, [Parameter(Mandatory=$true)] [String]$Uri, [Parameter()] [Array]$Body) # $res = (Invoke-WebRequest -Method "PUT" -Uri $Uri -Headers $Header -Body $Body -UseBasicParsing) # $res = '' + $res.StatusCode + ' ' + $res.StatusDescription $res = InvokeAsyncAnim { param($Uri, $Header, $Body) try { $res1 = (Invoke-WebRequest -Method 'PUT' -Uri $Uri -Headers $Header -Body $Body -UseBasicParsing) $res1 = '' + $res1.StatusCode + ' ' + $res1.StatusDescription; } catch { $res1 = 'Error: ' if(!$_.Exception.Response){ $res1 += $_.Exception.Message }else{ $ed = $_.Exception.Response.GetResponseStream() $reader = New-Object System.IO.StreamReader($ed) $responseBody = $reader.ReadToEnd(); $errorcontent = $responseBody | ConvertFrom-Json $res1 += '' + $errorcontent.error_code + ' ' + $errorcontent.message; } } return $res1 } return $res } Function XtremDELETERequest { Param( [Parameter(Mandatory=$true)] [Object]$Header, [Parameter(Mandatory=$true)] [String]$Uri, [Parameter()] [Array]$Body) $res = InvokeAsyncAnim { param($Uri, $Header, $Body) try { $res1 = (Invoke-WebRequest -Method 'DELETE' -Uri $Uri -Headers $Header -Body $Body -UseBasicParsing) $res1 = '' + $res1.StatusCode + ' ' + $res1.StatusDescription; } catch { $res1 = 'Error: ' if(!$_.Exception.Response){ $res1 += $_.Exception.Message }else{ $ed = $_.Exception.Response.GetResponseStream() $reader = New-Object System.IO.StreamReader($ed) $responseBody = $reader.ReadToEnd(); $errorcontent = $responseBody | ConvertFrom-Json $res1 += '' + $errorcontent.error_code + ' ' + $errorcontent.message; } } return $res1 } # $res = (Invoke-WebRequest -Method "DELETE" -Uri $Uri -Headers $Header -Body $Body -UseBasicParsing -ErrorAction Continue) # $res = '' + $res.StatusCode + ' ' + $res.StatusDescription return $res } #Builds the REST request Function NewXtremRequest { [cmdletbinding()] Param( [Parameter(Mandatory=$true)] [ValidateSet('GET','PUT','POST','DELETE')] [String]$Method, [Parameter(Mandatory=$true)] [String]$Endpoint, [Parameter()] $XtremClusterName, [Parameter()] [object]$Session, [Parameter()] [Object]$Body, [Parameter()] [Alias("Properties")] [String[]]$Property = $null, [Parameter()] [String]$ObjectSelection = '', [Parameter()] [String]$GetProperty = $null, [Parameter()] [Alias("Filters")] [Array]$Filter = $null, [Parameter()] [switch]$ShowRest, [Parameter()] [switch]$Multi = $false, [Parameter()] [switch]$Full = $false ) if($Session._XtremUsername) { $Username = $Session._XtremUsername $XmsName = $Session._XtremName if ($null -eq $XtremClusterName) { $XtremClusterName = $Session._XtremClusterName } $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Session._XtremPassword) $Password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR) } else { throw "Session was not created prior to this call" } $err = "" $result = "" #Special case...tags doesn't take cluster name and neither does performance if($Body -like "*cluster-id*") { $XtremClusterName = $null } if (($Endpoint -like '*xms*' -or $Endpoint -like '*clusters*' -or $Endpoint -like '*tags*' -or $Endpoint -like '*performance*') -and ($Method -eq 'GET' -or $Method -eq 'DELETE' )) { $XtremClusterName = $null } if (($Endpoint -like "*/remote-protections*") -and ($Method -eq 'PUT' )){ $XtremClusterName = $null } if(!$Body){ $Body = '{}' } try { ##Construct Auth Header and full URI $Header = GetXtremAuthHeader -username $username -password $password if ($Endpoint -like '*event*'){ $Uri = BuildURIRequest -endpoint $Endpoint -XmsName $XmsName -XtremClusterName $XtremClusterName -Properties $Property -GetProperty $GetProperty -Filters $Filter -Events } else { $Uri = BuildURIRequest -endpoint $Endpoint -XmsName $XmsName -XtremClusterName $XtremClusterName -Properties $Property -GetProperty $GetProperty -Filters $Filter -Full:$Full.IsPresent } showRestIfset $result = switch ($Method){ 'GET' { XtremGETRequest $Header $Endpoint $Uri } 'POST' { XtremPOSTRequest -Header $Header -Uri $Uri -Body $Body } 'PUT' { XtremPUTRequest -Header $Header -Uri $Uri -Body $Body } 'DELETE' { XtremDELETERequest -Header $Header -Uri $Uri -Body $Body } } } catch { $err = GetXtremErrorMsg -errordata $_ throw $err } return $result } # function decide if we should use a name or id and set up the parameters based on the choice. Function SetParametersForRequest { Param( [Parameter(Mandatory=$true)] $Route, [Parameter(Mandatory=$true)] $Name ) If ($Name.GetType().Name -eq "Int32" -or $Name.GetType().Name -eq "Object[]") { $Route = $Route + "/"+$Name return $Route,$null } $GetProperty = 'name='+ $Name return $Route,$GetProperty } function Set-XtremTrustAllCertsPolicy { <# .DESCRIPTION Set CertificatePolicy to trust all certs. This will remain in effect for this session. .NOTES Not sure where this originated. A few references: http://connect.microsoft.com/PowerShell/feedback/details/419466/new-webserviceproxy-needs-force-parameter-to-ignore-ssl-errors http://stackoverflow.com/questions/11696944/powershell-v3-invoke-webrequest-https-error .EXAMPLE Set-XtremTrustAllCertsPolicy #> [CmdletBinding()] Param( [Parameter()] [switch]$SilentWarnings=$false ) if([System.Net.ServicePointManager]::CertificatePolicy.ToString() -eq "TrustAllCertsPolicy") { # Write-Host "Current policy is already set to TrustAllCertsPolicy" } else { add-type @" using System.Net; using System.Security.Cryptography.X509Certificates; public class TrustAllCertsPolicy : ICertificatePolicy { public bool CheckValidationResult( ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) { return true; } } "@ [System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy } # if ($SilentWarnings -ne $true) { # Write-Warning "Please be aware that certificate validation was removed for the entire session." # } } function Get-XtremTypes { <# .DESCRIPTION This command (GET-XtremType) displays the list of all supported objects. .NOTES .EXAMPLE Get-XtremTypes #> [CmdletBinding()] Param( [parameter()] $XtremClusterName = (Get-XtremDefaultSession)._XtremClusterName, [Parameter()] [object]$Session = (Get-XtremDefaultSession), [Parameter()] [switch]$ShowRest ) $Route = '/types' $ObjectSelection = 'children' $result = NewXtremRequest -Method GET -endpoint $Route -Session $Session -SelectProps ('name') -XtremClusterName $XtremClusterName -ObjectSelection $ObjectSelection -ShowRest:$ShowRest.IsPresent return $result } Function AddIfExists($name,$value,$list) { <# Add a value to a list only if exists #> try { if ($value.GetType().Name -eq "Int32") { if ($null -ne $value) { $list.Add($name,$value) return } } if ($value) { $list.Add($name,$value) } } Catch { } return } Function IsConfirmed($confirmFlag) { # if flag suggest we always confirm (SDK state) confirm. if (($confirmFlag -eq $false)) { return $true; } $confirm = Read-Host("Are you sure you want to proceed (y/n) ? " ); if ($confirm -ieq 'y') { return $true } return $false } Function BuildXtremJson($list) { <# return a Json from a list #> return $list | ConvertTo-Json } Function Export-XtremCSV{ [Cmdletbinding()] Param( [Parameter(Mandatory=$true,ValueFromPipeline=$true)] [PSObject]$PerformanceData, [Parameter(Mandatory=$true)] [String]$ExportPath ) $data = $PerformanceData $members = $data.members $counters = $data.counters $dataarray = @() for($i = 0; $i -lt $counters.count; $i++) { $dataobj = New-Object System.Object [datetime]$EpochTime = '1970-01-01 00:00:00' for($j = 0; $j -lt $members.count; $j++) { #This is how I'm dealing with epoch time... if($j -eq 0) { $time = $EpochTime.AddMilliSeconds($counters[$i][$j]) $dataobj | Add-Member -type NoteProperty -name $members[$j] -Value $time } else { $dataobj | Add-Member -type NoteProperty -name $members[$j] -Value $counters[$i][$j] } } $dataarray = $dataarray + $dataobj } $sort_order = "timestamp" $dataarray |sort $sort_order | Export-Csv $ExportPath -NoTypeInformation } <# function Build-RESTcommandWidthDynamicParameter() { <# .DESCRIPTION Build step-by-step arbitrary REST request and get the results .PARAMETER type Type of the command .PARAMETER category Request category .PARAMETER request Request endpoint .PARAMETER entity Name of entity. .EXAMPLE Build-RESTcommand use [TAB] or [Ctrl+Space] .EXAMPLE Build-RESTcommand GET types volumes v1 # # > [cmdletbinding()] Param( [Parameter(Mandatory = $true)] [ValidateSet("GET", "POST", "PUT", "DELETE")] [string]$type, [Parameter(Mandatory = $true)] [ValidateSet("types", "commands")] [string]$category ) DynamicParam { $param1Attr = New-Object System.Management.Automation.ParameterAttribute $param2Attr = New-Object System.Management.Automation.ParameterAttribute $param1Attr.Mandatory = $true $param2Attr.Mandatory = $false $attrCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attrCollection2 = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attrCollection.Add($param1Attr) $attrCollection2.Add($param2Attr) $vals = getRequestsList $type $category $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary if ($vals) { $attrCollection.Add((New-Object System.Management.Automation.ValidateSetAttribute($vals))) $p1 = New-Object System.Management.Automation.RuntimeDefinedParameter('request', [string], $attrCollection) $paramDictionary.Add('request', $p1) } if ($PSBoundParameters.request){ $vals2 = getEntities $type $category $PSBoundParameters.request if ($vals2) { $attrCollection2.Add((New-Object System.Management.Automation.ValidateSetAttribute($vals2))) $paramDictionary.Add('entity', $p2) } $p1 = New-Object System.Management.Automation.RuntimeDefinedParameter('entity', [string], $attrCollection2) } return $paramDictionary } Process { $request = $PSBoundParameters.request $ent = $PSBoundParameters.entity return "$request $ent heh" } } #> # function Build-RESTcommand { # <# # .DESCRIPTION # Build step-by-step arbitrary REST request and get the results # .PARAMETER type # Type of the command (GET|POST|PUT|DELETE) # .PARAMETER category # Request category (type|command) # .PARAMETER endpoint # Request endpoint (ex. /volumes) # .PARAMETER entity # Name of entity (ex. name of volume) # .EXAMPLE # Build-RESTcommand use [TAB] or [Ctrl+Space] # .EXAMPLE # Build-RESTcommand GET types volumes v1 # #> # [CmdletBinding()] # param ( # [Parameter(Mandatory = $true)] # [ValidateSet("GET", "POST", "PUT", "DELETE")] # [string]$type, # [Parameter(Mandatory = $true)] # [ValidateSet("types", "commands")] # [string]$category, # [Parameter(Mandatory = $true)] # [string] # [ArgumentCompleter( { # param ( $commandName, # $parameterName, # $wordToComplete, # $commandAst, # $fakeBoundParameters ) # if ($fakeBoundParameters.ContainsKey('category')) { # $Route = "/$($fakeBoundParameters.category)" # $vals = (NewXtremRequest -Method GET -Endpoint $Route -Session (Get-XtremDefaultSession) -XtremClusterName '' -ObjectSelection 'children').name # if (!$vals) { # return "No_results_for_$Route" # }else{ # $vals | Where-Object { # $_ -like "$wordToComplete*" # } # } # } # } )] # $endpoint, # [Parameter(Mandatory = $false)] # [string] # [ArgumentCompleter( { # param ( $commandName, # $parameterName, # $wordToComplete, # $commandAst, # $fakeBoundParameters ) # if ($fakeBoundParameters.ContainsKey('category') -and $fakeBoundParameters.ContainsKey('endpoint')) { # $Route = "/$($fakeBoundParameters.category)/$($fakeBoundParameters.endpoint)" # $session = (Get-XtremDefaultSession) # $vals = (NewXtremRequest -Method GET -Endpoint $Route -Session $session -XtremClusterName $session._XtremClusterName -GetProperty "prop=guid&full=1").name # if(!$vals){ # return "No_results_for_$Route" # }else{ # $vals | Where-Object { # $_ -like "$wordToComplete*" # } | ForEach-Object { # New-Object -Type System.Management.Automation.CompletionResult -ArgumentList $_, "| $_ ", "ParameterValue", $_ # } # } # } # } )] # $entity # ) # $Route = "/$category/$endpoint" # if($type -eq 'GET'){ # $getProps = "full=1" # if($entity){ # $getProps += "&filter=name:eq:$entity" # } # Write-Host "$type $Route`?$getProps" # $session = (Get-XtremDefaultSession) # $res = NewXtremRequest -Method $type -Endpoint $Route -Session $session -XtremClusterName $session._XtremClusterName -GetProperty $getProps # $res # } # } function Invoke-XtremGetRequest { <# .DESCRIPTION Executes arbitrary GET request and get the results .PARAMETER path Endpoint path. .PARAMETER Property Query parameters array .PARAMETER Filter Filter by a property value. .EXAMPLE Build-RESTcommand use [TAB] or [Ctrl+Space] #> [CmdletBinding()] [Alias('xmsGet')] Param( [Parameter()] [string]$path, [Parameter()] [string[]]$Property, [parameter()] [Alias("Filters")] [array]$Filter ) $result = NewXtremRequest -Method GET -Session (Get-XtremDefaultSession) -Endpoint $path -Properties $Property -Filters $Filter return $result } function Get-XMScommand{ <# .DESCRIPTION Find XtremIO XMS command step-by-step using suggestions and autocomplete via [TAB] or [Ctrl+Space] .PARAMETER entity An entity against which you want to call an action. .PARAMETER action An action (verb) or action with subentity. .EXAMPLE xms Volume Modify (use [TAB] or [Ctrl+Space] to get suggestions) #> [CmdletBinding()] [Alias('xms')] Param( [Parameter()] [Argumentcompleter( { ' '; (New-Object -ComObject wscript.shell).SendKeys('{backspace}{tab}') })] [string]$entity, [Parameter()] [Argumentcompleter( { ' '; (New-Object -ComObject wscript.shell).SendKeys('{backspace}{tab}') })] [string]$action, [Parameter()] [string]$goToCommand ) if(!$entity) {return} if (!$action) { return} $theAlias = 'xms' + $entity + $action if (($xmsEntitiesList -contains $entity) -and (test-path alias:$theAlias)) { # move current entity to the first position # [void]($global:xmsEntitiesList.Remove($entity)) # [void]($global:xmsEntitiesList.Insert(0, $entity)) (New-Object -co wscript.shell).SendKeys($theAlias) } } $global:xmsEntitiesList = [System.Collections.ArrayList]('Volume', 'ConsistencyGroup', 'InitiatorGroup', 'Initiator', 'RemoteProtection', 'RetentionPolicy', 'QoS', 'Tag', 'Snapshot', 'SnapshotSet', 'LocalProtection', 'Copy', 'Session', 'Scheduler') $XmsEntityCompleter = { param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) $vals = $xmsEntitiesList if ($vals) { $vals | Where-Object { $_ -like "$wordToComplete*" } } } $XmsActionCompleter = { param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) $action = Get-Alias -Name "xms$($fakeBoundParameters.entity)*" | select name | where name -ne 'xms' | where name -notlike "xms$($fakeBoundParameters.entity)Group*" | where name -notlike "xms$($fakeBoundParameters.entity)Set*" | foreach { $_.name -replace "xms$($fakeBoundParameters.entity)", '' } $vals = $action if ($vals) { [void]($global:xmsEntitiesList.Remove($fakeBoundParameters.entity)) [void]($global:xmsEntitiesList.Insert(0, $fakeBoundParameters.entity)) $vals | Where-Object { $_ -like "$wordToComplete*" } } } $XmsGoToCommandCompleter = { param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) ' ' $keys = '{backspace}' * [int]$($commandAst.ToString().length+2) $keys += 'xms' + $fakeBoundParameters.entity + $fakeBoundParameters.action + ' {tab}' (New-Object -co wscript.shell).SendKeys($keys) } Register-ArgumentCompleter -Command Get-XMScommand -Param entity -ScriptBlock $XmsEntityCompleter Register-ArgumentCompleter -Command Get-XMScommand -Param action -ScriptBlock $XmsActionCompleter Register-ArgumentCompleter -Command Get-XMScommand -Param goToCommand -ScriptBlock $XmsGoToCommandCompleter # function getListOfAllCommands { # $allCommands = [System.Collections.ArrayList]((Get-Command -mod Xtremlib3).name) # $allAliases = [System.Collections.ArrayList]@() # foreach ($cmd in $allCommands) { # $al = (Get-Alias -Definition "$cmd" -ErrorAction 0).Name # foreach ($alias in $al) { # if ($alias.length -le 3) { continue } # if ($alias) { # [void]$allAliases.Add($alias) # } # } # } # $script:allCmdAls = $allCommands + $allAliases # } # function getCmdletUserParams($mod){ # $appParams = (Get-Command $parts[0]).Parameters # $paramsList = $appParams.Values.Name # $userProp = [ordered]@{ } # $ignoreList = @('XtremClusterName', 'Session', 'ShowRest', 'Full') # foreach ($nm in $paramsList) { # if($mod -eq 'main' -and $nm -in $ignoreList){ continue } # if ($mod -eq 'main' -and $nm -eq 'Verbose') { break } # $userProp[$nm] = $appParams[$nm].SwitchParameter # } # return $userProp # } function getCmdletUserParams($mod) { $appParams = (Get-Command $parts[0]).Parameters $paramsList = $appParams.Values.Name $userProp = [ordered]@{ } $ignoreList = @('XtremClusterName', 'Session', 'ShowRest', 'Full') foreach ($nm in $paramsList) { if ($mod -eq 'main' -and $nm -in $ignoreList) { continue } if ($mod -eq 'main' -and $nm -eq 'Verbose') { break } $isSwitch = $appParams[$nm].SwitchParameter $paramSet = $appParams[$nm].ParameterSets.Keys if ($paramSet -eq '__AllParameterSets') { $paramSet = $false } $userProp[$nm] = @{ isSwitch = $isSwitch paramSet = $paramSet } } return $userProp } function getNextParamToInsert ($isReverse) { $cmdParamsArr = ([array]$userParams.Keys) if ($line -notmatch " -\S+") { return $cmdParamsArr[0] } $lastParam = ([array](($line | Select-String " -\S+" -AllMatches).Matches.Value))[-1] $lastParam = ($lastParam -replace '-', '').Trim() if ($isReverse) { [array]::Reverse($cmdParamsArr) } $usedParamSets = [System.Collections.ArrayList]@() foreach ($nm in $cmdParamsArr) { $paramSet = $userParams[$nm].paramSet if ($useNext -and ($line -notlike "* -$nm*")) { if ($paramSet -and ($usedParamSets -and $paramSet -notin $usedParamSets)) { continue } return $nm } if ($nm -eq $lastParam) { $useNext = $true } if ($paramSet){ if($line -like "* -$nm* "){ [void]$usedParamSets.Add($paramSet) } } } return '' } function countUsedParams($parts){ $count = 0 foreach ($part in $parts){ if($part -eq $parts[0]){continue} if($part -notlike "-*"){ # is value $count++ }elseif ( $userParams[($part -replace '-','')] ){ # is switch $count++ } } return $count } function lineHandleQuotedStings{ # replace long strings in quotes, they may contain spaces $line = $line -replace ("\'[^\']+\'"), "_" $line = $line -replace ('\"[^\"]+\"'), '_' return $line } # Add-Type -AssemblyName PresentationCore, PresentationFramework # function setKeyHandlers{ # setting keyboard shortcuts if PSReadLine is installed, it is by default since PS v.5.0 if (Get-Command Set-PSReadLineKeyHandler -errorAction SilentlyContinue) { Set-PSReadLineKeyHandler -Chord Tab -ScriptBlock { tabHandle $args } Set-PSReadLineKeyHandler -Chord Shift+Tab -ScriptBlock { shiftTabHandle $args } Set-PSReadLineKeyHandler -Chord Backspace -ScriptBlock { backSpaceHandle $args } Set-PSReadLineKeyHandler -Chord Ctrl+Spacebar -ScriptBlock { cntrlSpaceHandle $args } Set-PSReadLineKeyHandler -Chord Spacebar -ScriptBlock { spaceBarHandle $args } Set-PSReadLineKeyHandler -Chord Shift+Oem5 -ScriptBlock { pipeHandle $args } Set-PSReadLineKeyHandler -Chord Enter -ScriptBlock { enterHandle $args } # search latest XMS commands in history # Set-PSReadLineKeyHandler -Chord Ctrl+UpArrow -ScriptBlock { # $line = $null # $cursor = $null # [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) # $vals = getXMSHistoryCommands # if ($XtremDefaultSessionObject){ # if (!$line) { # if($vals -and $vals.length -ge 0){ # $item = $vals[$vals.length - 1] # [Microsoft.PowerShell.PSConsoleReadLine]::Insert($item+' '); # } # }elseif ($vals -contains $line.Trim()){ # $ind = [array]::IndexOf($vals, $line.Trim()) # if($ind -ge 1){ # $item = $item = $vals[$ind - 1] # [Microsoft.PowerShell.PSConsoleReadLine]::RevertLine(); # [Microsoft.PowerShell.PSConsoleReadLine]::Insert($item+' '); # } # } # } # } # scroll down in XMS commands in history # Set-PSReadLineKeyHandler -Chord Ctrl+DownArrow -ScriptBlock { # $line = $null # $cursor = $null # [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) # $vals = getXMSHistoryCommands # if ($XtremDefaultSessionObject) { # if (!$line) { # } # elseif ($vals -contains $line.Trim()) { # $ind = [array]::IndexOf($vals, $line.Trim()) # if ($ind -le $vals.length-2) { # $item = $item = $vals[$ind + 1] # [Microsoft.PowerShell.PSConsoleReadLine]::RevertLine(); # [Microsoft.PowerShell.PSConsoleReadLine]::Insert($item+' '); # } # } # } # } } # } function enterHandle($sbArgs) { $key, $arg = $sbArgs $line, $cursor = $null, $null [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) $isLineEnd = ($line.Substring(0, $cursor ) -eq $line) $parts = $line -split " " if (($parts[0] -eq 'xms') -and ($parts.length -eq 3) -and $isLineEnd) { $entity = $parts[1] if ($xmsEntitiesList -contains $entity){ $action = $parts[2] $theAlias = 'xms' + $entity + $action if (test-path alias:$theAlias) { [Microsoft.PowerShell.PSConsoleReadLine]::RevertLine(); [Microsoft.PowerShell.PSConsoleReadLine]::Insert($theAlias); } } } [Microsoft.PowerShell.PSConsoleReadLine]::AcceptLine(); } function pipeHandle($sbArgs){ $key, $arg = $sbArgs $line, $cursor = $null, $null [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) $isLineEnd = ($line.Substring(0, $cursor ) -eq $line) $parts = $line -split " " if (($parts[0] -eq 'xms') -and ($parts.length -eq 3) -and $isLineEnd) { $entity = $parts[1] if ($xmsEntitiesList -contains $entity) { $action = $parts[2] $theAlias = 'xms' + $entity + $action if (test-path alias:$theAlias) { [Microsoft.PowerShell.PSConsoleReadLine]::RevertLine(); [Microsoft.PowerShell.PSConsoleReadLine]::Insert($theAlias); } } } if (($line.length -gt 0) -and $isLineEnd){ $addSpace = ' ' $spaceAtTheEnd = $line.substring($line.length-1) -eq ' ' if($spaceAtTheEnd){ $addSpace = '' } [Microsoft.PowerShell.PSConsoleReadLine]::Insert($addSpace + '|' + ' '); }else{ [Microsoft.PowerShell.PSConsoleReadLine]::Insert('|'); } } function tabHandle($sbArgs){ $key, $arg = $sbArgs $line, $cursor = $null, $null [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) $isLineEnd = ($line.Substring(0, $cursor ) -eq $line) if ($XtremDefaultSessionObject){ if (!$line) { [Microsoft.PowerShell.PSConsoleReadLine]::Insert('xms '); }elseif ($isLineEnd){ $line = lineHandleQuotedStings $parts = $line -split " " $userParams = getCmdletUserParams ('all') $cmdParamsArr = ([Array]$userParams.Keys) $lastWordIsParam = (($parts[-1] -like "-*") -and (($parts[-1] -replace "^-", '') -in $cmdParamsArr) ) # $countLineParams = ([array](($line | Select-String " -\S+" -AllMatches).Matches.Value)).Count # $haveMoreParams = $countLineParams -lt $cmdParamsArr.Count $nextParam = getNextParamToInsert if($lastWordIsParam -and $nextParam){ [Microsoft.PowerShell.PSConsoleReadLine]::BackwardWord(); [Microsoft.PowerShell.PSConsoleReadLine]::DeleteWord(); [Microsoft.PowerShell.PSConsoleReadLine]::MoveToEndOfLine(); [Microsoft.PowerShell.PSConsoleReadLine]::Insert( $nextParam ); }else{ [Microsoft.PowerShell.PSConsoleReadLine]::TabCompleteNext(); } }else{ [Microsoft.PowerShell.PSConsoleReadLine]::TabCompleteNext(); } }else{ [Microsoft.PowerShell.PSConsoleReadLine]::TabCompleteNext(); } } function shiftTabHandle($sbArgs){ $key, $arg = $sbArgs $line, $cursor = $null, $null [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) $isLineEnd = ($line.Substring(0, $cursor ) -eq $line) if ($isLineEnd){ $line = lineHandleQuotedStings $parts = $line -split " " $userParams = getCmdletUserParams ('all') $cmdParamsArr = ([Array]$userParams.Keys) $lastWordIsParam = (($parts[-1] -like "-*") -and (($parts[-1] -replace "^-", '') -in $cmdParamsArr) ) # $countLineParams = ([array](($line | Select-String " -\S+" -AllMatches).Matches.Value)).Count # $haveMoreParams = $countLineParams -lt $cmdParamsArr.Count $nextParam = getNextParamToInsert $true if($lastWordIsParam -and $nextParam){ [Microsoft.PowerShell.PSConsoleReadLine]::BackwardWord(); [Microsoft.PowerShell.PSConsoleReadLine]::DeleteWord(); [Microsoft.PowerShell.PSConsoleReadLine]::MoveToEndOfLine(); [Microsoft.PowerShell.PSConsoleReadLine]::Insert( $nextParam ); }else{ [Microsoft.PowerShell.PSConsoleReadLine]::TabCompletePrevious(); } }else{ [Microsoft.PowerShell.PSConsoleReadLine]::TabCompletePrevious(); } } function backSpaceHandle($sbArgs){ $key, $arg = $sbArgs $line, $cursor = $null, $null [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) if(!$line){ return } $isLineEnd = ($line.Substring(0, $cursor ) -eq $line) $parts = $line -split " " if ($isLineEnd -and ($parts[-1] -like "-*")) { $userParams = getCmdletUserParams ('all') $cmdParamsArr = ([Array]$userParams.Keys) $lastWordIsParam = (($parts[-1] -like "-*") -and (($parts[-1] -replace "^-", '') -in $cmdParamsArr) ) if ($lastWordIsParam ) { [Microsoft.PowerShell.PSConsoleReadLine]::BackwardWord(); [Microsoft.PowerShell.PSConsoleReadLine]::DeleteWord(); [Microsoft.PowerShell.PSConsoleReadLine]::MoveToEndOfLine(); } else { [Microsoft.PowerShell.PSConsoleReadLine]::BackwardDeleteChar(); } }else{ [Microsoft.PowerShell.PSConsoleReadLine]::BackwardDeleteChar(); } } function cntrlSpaceHandle($sbArgs){ $key, $arg = $sbArgs $line, $cursor = $null, $null [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) if (!$line -and $XtremDefaultSessionObject) { [Microsoft.PowerShell.PSConsoleReadLine]::Insert('xms '); } [Microsoft.PowerShell.PSConsoleReadLine]::MenuComplete(); } function spaceBarHandle($sbArgs){ $key, $arg = $sbArgs $line, $cursor = $null, $null [Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor) $isLineEnd = ($line.Substring(0, $cursor ) -eq $line) # $line = $line.Trim() $line = $line + ' ' $line = lineHandleQuotedStings $parts = ($line.Trim()) -split " " # [System.Windows.MessageBox]::Show("$($arg) " , 'Message') if(!$isLineEnd -or ($line -match "\|")){ [Microsoft.PowerShell.PSConsoleReadLine]::Insert(' ') return } if ($parts[0] -eq 'xms') { # xms command builder/navigation section (eg. xms Volume Get => xmsVolumeGet) if ($parts[2] -and $parts[2].Length -ge 3) { $theAlias = $parts -join "" if (test-path alias:$theAlias) { [Microsoft.PowerShell.PSConsoleReadLine]::RevertLine() [Microsoft.PowerShell.PSConsoleReadLine]::Insert($theAlias) (New-Object -ComObject wscript.shell).SendKeys(' ') # [Microsoft.PowerShell.PSConsoleReadLine]::Insert(' ') } }else{ [Microsoft.PowerShell.PSConsoleReadLine]::Insert(' ') } }elseif (isXmsCommand){ # show properties of xms commands section $userParams = getCmdletUserParams ('main') $noParamsYet = ($parts[-1] -eq $parts[0]) $lastWordIsValueOrSwitch = (($parts[-1] -notLike "-*") -or ($userParams[($parts[-1] -replace "^-",'')].isSwitch) ) # $haveMoreParams = ((countUsedParams ($parts)) -lt $userParams.Keys.Count) $nextParam = getNextParamToInsert if(($noParamsYet -or $lastWordIsValueOrSwitch) -and $nextParam){ [Microsoft.PowerShell.PSConsoleReadLine]::Insert(' -') [Microsoft.PowerShell.PSConsoleReadLine]::Insert( $nextParam ) # (New-Object -ComObject wscript.shell).SendKeys('{tab}') }else{ [Microsoft.PowerShell.PSConsoleReadLine]::Insert(' ') } }else{ [Microsoft.PowerShell.PSConsoleReadLine]::Insert(' ') } } function isXmsCommand(){ if($parts[0].length -gt 3){ if($parts[0] -like "*-Xtrem*" -or $parts[0] -like "xms*"){ return $true } } return $false } function getXMSHistoryCommands(){ $fPath = (Get-PSReadlineOption).HistorySavePath $arr = Get-Content $fPath | Select-String -pattern "^xms[A-Za-z]+ .+" $vals = $arr.line | foreach { $a = ($_ -split ' '); $a[0] } | Get-Unique [array]::Reverse($vals) $vals = $vals | select -Unique [array]::Reverse($vals) return $vals } Export-ModuleMember Get-XMScommand -Alias * # Export-ModuleMember Build-RESTcommand Export-ModuleMember Invoke-XtremGetRequest -Alias * Export-ModuleMember GetXtremErrorMsg Export-ModuleMember GetXtremAuthHeader # Export-ModuleMember GetXtremRawRequest # Export-ModuleMember CreateResponseObject Export-ModuleMember BuildURIRequest Export-ModuleMember XtremGETRequest Export-ModuleMember XtremPUTRequest Export-ModuleMember XtremDELETERequest Export-ModuleMember NewXtremRequest Export-ModuleMember SetParametersForRequest Export-ModuleMember Set-XtremTrustAllCertsPolicy Export-ModuleMember Export-XtremCSV Export-ModuleMember BuildXtremJson Export-ModuleMember IsConfirmed Export-ModuleMember AddIfExists # Export-ModuleMember Get-XTremType |