Looking at the Isilon Platform API introduced with OneFS 7.0.2, which is using REST with JSON for communication, I was struggling how to start. At first I tried to use Perl for scripting but as I’m not very experienced in Perl, I was quickly frustrated. Luckily I stumbled across Powershell for REST scripting.
After searching a little bit I found two great blogs ([1] [2]) which helped me as a good starting point.
Powershell:
Powershell 3.0 introduced a couple of very handy cmdlets for scripting with REST and Json:
ConvertTo-Json ConvertFrom-Json Invoke-RestMethod
Powershell 3.0 is available for Windows 7, Windows Server 2008 and its successors.
Powershell 4.0 just recently released and has also some improvements and fixes for the “Invoke-RestMethod” included.
JSON:
The first two cmdlets are great as you don’t need to have any JSON knowledge to generate JSON code. You can simply create a standard Powershell Object and convert it to a JSON Object. This can be done also vice versa.
Here is a simple example to generate the JSON Object for creating a new share. At first we are creating the Powershell object with the required properties “name” and “path”:
$obj = [pscustomobject]@{} $share = "share1" $path = "/ifs/data/share1" Add-Member -InputObject $obj -type NoteProperty -name name -value $share Add-Member -InputObject $obj -type NoteProperty -name path -value $path $obj
The last line will output our share as a Powershell Object:
name : share1 path : /ifs/data/share1
Secondly we apply the “ConvertTo-Json” cmdlet to create the corresponding JSON object:
$jobj = ConvertTo-Json $obj $jobj
And its output:
{ "name": "share1", "path": "/ifs/data/share1" }
With these two cmdlets we are able to work with JSON without knowing the syntax. I personal think this is great.
Invoke-RestMethod:
The next step is to communicate with the Isilon Platform API using the third cmdlet “Invoke-RestMethod”. The Isilon REST implementation is using the HTTP(s) protocol and JSON for the body.
Invoke-RestMethod [-Uri <Uri>] [-Body <Object> ] [-ContentType <String> ] [-Headers <IDictionary> ] [-Method <WebRequestMethod> ] [-SessionVariable <String> ] [-WebSession <WebRequestSession> ]
The list of parameters reflects only the ones we will use and is not complete:
-Uri <Uri>
Specifies the Uniform Resource Identifier (URI) of the Internet resource to which the web request is sent.
In our case this will be the URI to the Isilon resource. For our share example: “https://isilon:8080/platform/1/protocols/smb/shares”
-Body <Object>
Specifies the body of the request. The body is the content of the request that follows the headers.
Here we will enter our JSON Object, for our share example:”$jobj”
-ContentType <String>
Specifies the content type of the web request.
If we are going to sent to the API a body, we have to define the format. This will be “application/json; charset=utf-8”.
-Method <WebRequestMethod>
Specifies the method used for the web request.
Use “GET” for retrieving, “POST” for creating, “PUT” for modifying and “DELETE” for deleting an object.
For authenticating with the Isilon API we can leverage two different methods. On one side we can send with every call a basic authentication header and therefore use the “headers” parameter. On the other hand we can create a session (“SessionVariable”) and successive send only the cookie(“WebSession”).
Using headers is simpler but requires more Isilon resources as every request has to be authenticated. Also you will have to store you username and password somewhere if you are working in the powershell.
-Headers <IDictionary>
Specifies the headers of the web request. Enter a hash table or dictionary.
-SessionVariable <String>
Creates a web request session and saves it in the value of the specified variable.
-WebSession <WebRequestSession>
Specifies a web request session.
Example:
To give you an idea of the cmdlet and its output we are creating the SMB share from the example above, using header authentication, and retrieve the share object afterwards:
# create header $username = "root" $password = "a" $EncodedAuthorization = [System.Text.Encoding]::UTF8.GetBytes($username + ':' + $password) $EncodedPassword = [System.Convert]::ToBase64String($EncodedAuthorization) $headers = @{"Authorization"="Basic $($EncodedPassword)"} # create Uri $isilonip = "10.0.0.1" $baseurl = 'https://' + $isilonip +":8080" $resourceurl = "/platform/1/protocols/smb/shares" $uri = $baseurl + $resourceurl # create share object $obj = [pscustomobject]@{} $share = "share1" $path = "/ifs/data/share1" Add-Member -InputObject $obj -type NoteProperty -name name -value $share Add-Member -InputObject $obj -type NoteProperty -name path -value $path $jobj = ConvertTo-Json $obj # send request to create share $ISIObject = Invoke-RestMethod -Uri $uri -Method Post -Headers $headers -Body $jobj -ContentType "application/json; charset=utf-8"
After creating the share we are retreaving the object and printing the Powershell object:
# get share and print $uri = $baseurl + $resourceurl + '/' + $share $ISIObject = Invoke-RestMethod -Uri $uri -Method Get -Headers $headers $ISIObject.shares
Output:
access_based_enumeration : False access_based_enumeration_root_only : False allow_delete_readonly : False allow_execute_always : False allow_variable_expansion : False auto_create_directory : False browsable : True change_notify : norecurse create_permissions : default acl csc_policy : manual description : directory_create_mask : 448 directory_create_mode : 0 file_create_mask : 448 file_create_mode : 64 hide_dot_files : False host_acl : {} id : share1 impersonate_guest : never impersonate_user : inheritable_path_acl : False mangle_byte_start : 60672 mangle_map : {0x01-0x1F:-1, 0x22:-1, 0x2A:-1, 0x3A:-1...} name : share1 ntfs_acl_support : True oplocks : True path : /ifs/data/share1 permissions : {@{permission=read; permission_type=allow; trustee=}} run_as_root : {} strict_flush : True strict_locking : False
SSL Validation:
If you are using the default self signed certificate of the Isilon your code will probably fail with the following error:
Invoke-RestMethod : The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.
This happens because the Isilon generates by default a self signed certificate. To alleviate this you can disable the certificate validation for the current Powershell session with following code:
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
Update:
Curiously this does not work with Session Authentication (explained in Part2) and fails with following error:
Invoke-RestMethod : The underlying connection was closed: An unexpected error occurred on a send.
To reliably disable SSL validation please you following code, written by Matt Graeber, which can also be found on PoshCode:
function Disable-SSLValidation{ <# .SYNOPSIS Disables SSL certificate validation .DESCRIPTION Disable-SSLValidation disables SSL certificate validation by using reflection to implement the System.Net.ICertificatePolicy class. Author: Matthew Graeber (@mattifestation) License: BSD 3-Clause .NOTES Reflection is ideal in situations when a script executes in an environment in which you cannot call csc.ese to compile source code. If compiling code is an option, then implementing System.Net.ICertificatePolicy in C# and Add-Type is trivial. .LINK http://www.exploit-monday.com #> Set-StrictMode -Version 2 # You have already run this function if ([System.Net.ServicePointManager]::CertificatePolicy.ToString() -eq 'IgnoreCerts') { Return } $Domain = [AppDomain]::CurrentDomain $DynAssembly = New-Object System.Reflection.AssemblyName('IgnoreCerts') $AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run) $ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('IgnoreCerts', $false) $TypeBuilder = $ModuleBuilder.DefineType('IgnoreCerts', 'AutoLayout, AnsiClass, Class, Public, BeforeFieldInit', [System.Object], [System.Net.ICertificatePolicy]) $TypeBuilder.DefineDefaultConstructor('PrivateScope, Public, HideBySig, SpecialName, RTSpecialName') | Out-Null $MethodInfo = [System.Net.ICertificatePolicy].GetMethod('CheckValidationResult') $MethodBuilder = $TypeBuilder.DefineMethod($MethodInfo.Name, 'PrivateScope, Public, Virtual, HideBySig, VtableLayoutMask', $MethodInfo.CallingConvention, $MethodInfo.ReturnType, ([Type[]] ($MethodInfo.GetParameters() | % {$_.ParameterType}))) $ILGen = $MethodBuilder.GetILGenerator() $ILGen.Emit([Reflection.Emit.Opcodes]::Ldc_I4_1) $ILGen.Emit([Reflection.Emit.Opcodes]::Ret) $TypeBuilder.CreateType() | Out-Null # Disable SSL certificate validation [System.Net.ServicePointManager]::CertificatePolicy = New-Object IgnoreCerts }
Conclusion:
Powershell v3+ offers you a great platform for scripting with the Isilon PAPI. You can write rich scripts without the need to learn JSON and/or write your own methods for communication.
I will discuss authentication and the usage of “Invoke-RestMethod” with Isilon in Part 2 in more depth.
[1] http://muegge.com/blog/?p=251
[2] https://community.emc.com/community/connect/isilon/blog/2013/09/25/using-powershell-with-the-papi-and-ran–the-basics