From 2df85e91bb152662363168bf99337cb65d94151e Mon Sep 17 00:00:00 2001 From: Tome Tanasovski Date: Sun, 20 Apr 2014 00:11:50 -0400 Subject: [PATCH 01/10] Issue #1 Allow cmdlets to use multiple parameter sets --- Odata.psm1 | 47 ++++++--- tests/Odata.tests.ps1 | 107 +++++++++----------- tests/validate_schema.xml | 206 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 289 insertions(+), 71 deletions(-) create mode 100644 tests/validate_schema.xml diff --git a/Odata.psm1 b/Odata.psm1 index 59b76b5..76d7c91 100644 --- a/Odata.psm1 +++ b/Odata.psm1 @@ -19,6 +19,11 @@ $rbacconfigtemplate = @' '@ + +# Following is a list of parameternames to ignore when creating the parameterlist section in schema.xml +$paramignorelist = @('PipelineVariable','OutBuffer','OutVariable','WarningVariable','ErrorVariable','WarningAction', + 'ErrorAction','Debug','Verbose') + function New-OdataClass { param( [Parameter(Mandatory=$true, Position=0)] @@ -173,20 +178,7 @@ function ConvertTo-ClassXML{ $text += $paramtext } $allparams = $class.($verb).Parameters + $class.($verb).FilterParameters |select -Unique - if ($allparams) { - $paramtext = " "*10 + "`r`n" - $paramtext += " "*12 + "`r`n" - $paramtext += " "*14 + "Default`r`n" - foreach ($parameter in ($allparams)) { - $paramtext += " "*14 + "`r`n" - $paramtext += (" "*16 + "{0}`r`n") -f $parameter - $paramtext += " "*16 + "System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089`r`n" - $paramtext += " "*14 + "`r`n" - } - $paramtext += " "*12 + "`r`n" - $paramtext += " "*10 + "`r`n" - $text += $paramtext - } + $text += Get-ParameterSetXML $class.($verb).cmdlet $text += " "*8 + "`r`n" } } @@ -220,3 +212,30 @@ class mosd_{0} $text += "};`r`n" $text } + +function Get-ParameterSetXML { + param( + [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)] + [ValidateScript({get-command $_})] + [String] $Cmdlet + ) + $text = " "*10 + "`r`n" + foreach ($parameterset in (get-command $cmdlet |select -ExpandProperty parametersets)) { + $text += " "*12 + "`r`n" + $text += " "*14 + "{0}`r`n" -f $parameterset.name + foreach ($parameter in ($parameterset.Parameters)) { + if ($paramignorelist -notcontains $parameter.name) { + $text += " "*14 + "`r`n" + $text += " "*16 + "{0}`r`n" -f $parameter.name + $text += " "*16 + "System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089`r`n" + if ($parameter.IsMandatory) { + $text += " "*16 + "True`r`n" + } + $text += " "*14 + "`r`n" + } + } + $text += " "*12 + "`r`n" + } + $text += " "*10 + "`r`n" + $text +} diff --git a/tests/Odata.tests.ps1 b/tests/Odata.tests.ps1 index d5bc6d5..491eb68 100644 --- a/tests/Odata.tests.ps1 +++ b/tests/Odata.tests.ps1 @@ -36,7 +36,7 @@ Describe "Add-OdataMethod" { $class.update|should BeNullOrEmpty } It "Creates a DELETE method" { - $class |set-odatamethod -verb delete -cmdlet stop-process -FilterParams ID -params ID + $class |set-odatamethod -verb delete -cmdlet stop-process -FilterParams ID,name -params ID,name } It "Fails if verb is not valid" { {$class |set-odatamethod -verb blah -cmdlet dir -pk ID -Params Name, ID -FilterParams Name} |should Throw @@ -46,6 +46,53 @@ Describe "Add-OdataMethod" { } } +function CommandWith2ParamSets { + param( + [Parameter(Mandatory=$true,ParameterSetName="set1")] + [string] $set1param, + [Parameter(Mandatory=$true,ParameterSetName="set2")] + [string] $set2param, + [Parameter(Mandatory=$false)] + [switch] $switchparam + ) +} +Describe "Get-ParameterSetXML" { + It "Does not work with an invalid command" { + {Get-ParameterSetXML 'lskdfjlsdfjlksdfjljdfkljdsf'} |should Throw + } + It "Converts the ParameterSet of a command into appropriate schema.xml syntax" { + Get-ParameterSetXML CommandWith2ParamSets |Should be @' + + + set1 + + set1param + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + True + + + switchparam + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + set2 + + set2param + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + True + + + switchparam + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + +'@ + } +} + Describe "ConvertTo-MofText" { It "Converts a class to the text required in a Mof file" { $class |ConvertTo-MofText |Should be @' @@ -71,63 +118,10 @@ Describe "ConvertTo-ResourceXML" { } } +$validatexml = [IO.file]::ReadAllText((join-path tests validate_schema.xml)) Describe "ConvertTo-ClassXML" { It "Converts a class to the text needed in the class section of the schema.xml" { - $class |ConvertTo-ClassXML |Should be @' - - mosd_Process - - - get-process - - Name - ID - - - - Name - Name - - - - - Default - - Name - System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - ID - System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - - - - stop-process - - ID - - - - ID - ID - - - - - Default - - ID - System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - - - - - -'@ + $class |ConvertTo-ClassXML |Should be $validatexml } } @@ -167,4 +161,3 @@ Describe "New-OdataEndpoint" { # cleanup the directory created during the tests rm (join-path $here odata) -recurse -#TODO consider moving validation text into validator files in the /tests directory diff --git a/tests/validate_schema.xml b/tests/validate_schema.xml new file mode 100644 index 0000000..c4548f6 --- /dev/null +++ b/tests/validate_schema.xml @@ -0,0 +1,206 @@ + + mosd_Process + + + get-process + + Name + ID + + + + Name + Name + + + + + Name + + Name + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ComputerName + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Module + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + FileVersionInfo + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + NameWithUserName + + Name + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + IncludeUserName + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + True + + + + IdWithUserName + + Id + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + True + + + IncludeUserName + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + True + + + + Id + + Id + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + True + + + ComputerName + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Module + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + FileVersionInfo + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + InputObjectWithUserName + + InputObject + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + True + + + IncludeUserName + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + True + + + + InputObject + + InputObject + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + True + + + ComputerName + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Module + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + FileVersionInfo + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + stop-process + + ID + name + + + + ID + ID + name + name + + + + + Id + + Id + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + True + + + PassThru + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Force + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + WhatIf + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Confirm + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Name + + Name + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + True + + + PassThru + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Force + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + WhatIf + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Confirm + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + InputObject + + InputObject + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + True + + + PassThru + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Force + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + WhatIf + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Confirm + System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + From c7699e78a4e9c1e21ed514d2cc7e45f43526b867 Mon Sep 17 00:00:00 2001 From: Tome Tanasovski Date: Sun, 20 Apr 2014 00:16:38 -0400 Subject: [PATCH 02/10] Issue #15 FieldParameterMap not correct with multiple field parameters --- Odata.psm1 | 4 ++-- tests/validate_schema.xml | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Odata.psm1 b/Odata.psm1 index 76d7c91..246c5c2 100644 --- a/Odata.psm1 +++ b/Odata.psm1 @@ -168,12 +168,12 @@ function ConvertTo-ClassXML{ # Add Filter parameters/FieldParameterMap section if ($class.($verb).FilterParameters) { $paramtext = " "*10 + "`r`n" - $paramtext += " "*12 + "`r`n" foreach ($parameter in ($class.($verb).FilterParameters)) { + $paramtext += " "*12 + "`r`n" $paramtext += (" "*14 + "{0}`r`n") -f $parameter $paramtext += (" "*14 + "{0}`r`n") -f $parameter + $paramtext += " "*12 + "`r`n" } - $paramtext += " "*12 + "`r`n" $paramtext += " "*10 + "`r`n" $text += $paramtext } diff --git a/tests/validate_schema.xml b/tests/validate_schema.xml index c4548f6..7cf7752 100644 --- a/tests/validate_schema.xml +++ b/tests/validate_schema.xml @@ -123,6 +123,8 @@ ID ID + + name name From 613c45e9c002c28d0e5cbbf58a73e5c298631914 Mon Sep 17 00:00:00 2001 From: Tome Tanasovski Date: Mon, 21 Apr 2014 14:35:03 -0400 Subject: [PATCH 03/10] Issue #14 - Refactoring of string lines with -f --- Odata.psm1 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Odata.psm1 b/Odata.psm1 index 246c5c2..112d148 100644 --- a/Odata.psm1 +++ b/Odata.psm1 @@ -152,15 +152,15 @@ function ConvertTo-ClassXML{ } else { $section = $verb } - $text += " "*8 + ("<{0}>`r`n" -f $section) - $text += " "*10 + ("{0}`r`n" -f $class.($verb).Cmdlet) + $text += " "*8 + "<{0}>`r`n" -f $section + $text += " "*10 + "{0}`r`n" -f $class.($verb).Cmdlet $text += $verbtext -f $section, $class.($verb).Cmdlet # Add Parameters/Options section if ($class.($verb).Parameters) { $paramtext = " "*10 + "`r`n" foreach ($parameter in ($class.($verb).Parameters)) { - $paramtext += (" "*12 + "{0}`r`n") -f $parameter + $paramtext += " "*12 + "{0}`r`n" -f $parameter } $text += $paramtext + " "*10 + "`r`n" } @@ -170,8 +170,8 @@ function ConvertTo-ClassXML{ $paramtext = " "*10 + "`r`n" foreach ($parameter in ($class.($verb).FilterParameters)) { $paramtext += " "*12 + "`r`n" - $paramtext += (" "*14 + "{0}`r`n") -f $parameter - $paramtext += (" "*14 + "{0}`r`n") -f $parameter + $paramtext += " "*14 + "{0}`r`n" -f $parameter + $paramtext += " "*14 + "{0}`r`n" -f $parameter $paramtext += " "*12 + "`r`n" } $paramtext += " "*10 + "`r`n" From 59ab3a2ca26e40fa1fcf1c461dfc2801882b6a43 Mon Sep 17 00:00:00 2001 From: Tome Tanasovski Date: Mon, 21 Apr 2014 15:09:25 -0400 Subject: [PATCH 04/10] Issue #3 Support the Switch type in parameterset section of schema.xml --- Odata.psm1 | 7 ++++- tests/Odata.tests.ps1 | 6 ++-- tests/validate_schema.xml | 63 ++++++++++++++++++++++++++------------- 3 files changed, 52 insertions(+), 24 deletions(-) diff --git a/Odata.psm1 b/Odata.psm1 index 112d148..fa7a5f1 100644 --- a/Odata.psm1 +++ b/Odata.psm1 @@ -227,7 +227,12 @@ function Get-ParameterSetXML { if ($paramignorelist -notcontains $parameter.name) { $text += " "*14 + "`r`n" $text += " "*16 + "{0}`r`n" -f $parameter.name - $text += " "*16 + "System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089`r`n" + if ($parameter.ParameterType.ToString() -eq 'System.Management.Automation.SwitchParameter') { + $text += " "*16 + "System.Management.Automation.SwitchParameter, System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35`r`n" + $text += " "*16 + "True`r`n" + } else { + $text += " "*16 + "System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089`r`n" + } if ($parameter.IsMandatory) { $text += " "*16 + "True`r`n" } diff --git a/tests/Odata.tests.ps1 b/tests/Odata.tests.ps1 index 491eb68..53f3b95 100644 --- a/tests/Odata.tests.ps1 +++ b/tests/Odata.tests.ps1 @@ -72,7 +72,8 @@ Describe "Get-ParameterSetXML" { switchparam - System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Management.Automation.SwitchParameter, System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 + True @@ -84,7 +85,8 @@ Describe "Get-ParameterSetXML" { switchparam - System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Management.Automation.SwitchParameter, System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 + True diff --git a/tests/validate_schema.xml b/tests/validate_schema.xml index 7cf7752..0937d1d 100644 --- a/tests/validate_schema.xml +++ b/tests/validate_schema.xml @@ -26,11 +26,13 @@ Module - System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Management.Automation.SwitchParameter, System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 + True FileVersionInfo - System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Management.Automation.SwitchParameter, System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 + True @@ -41,7 +43,8 @@ IncludeUserName - System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Management.Automation.SwitchParameter, System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 + True True @@ -54,7 +57,8 @@ IncludeUserName - System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Management.Automation.SwitchParameter, System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 + True True @@ -71,11 +75,13 @@ Module - System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Management.Automation.SwitchParameter, System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 + True FileVersionInfo - System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Management.Automation.SwitchParameter, System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 + True @@ -87,7 +93,8 @@ IncludeUserName - System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Management.Automation.SwitchParameter, System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 + True True @@ -104,11 +111,13 @@ Module - System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Management.Automation.SwitchParameter, System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 + True FileVersionInfo - System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Management.Automation.SwitchParameter, System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 + True @@ -139,19 +148,23 @@ PassThru - System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Management.Automation.SwitchParameter, System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 + True Force - System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Management.Automation.SwitchParameter, System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 + True WhatIf - System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Management.Automation.SwitchParameter, System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 + True Confirm - System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Management.Automation.SwitchParameter, System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 + True @@ -163,19 +176,23 @@ PassThru - System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Management.Automation.SwitchParameter, System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 + True Force - System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Management.Automation.SwitchParameter, System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 + True WhatIf - System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Management.Automation.SwitchParameter, System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 + True Confirm - System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Management.Automation.SwitchParameter, System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 + True @@ -187,19 +204,23 @@ PassThru - System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Management.Automation.SwitchParameter, System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 + True Force - System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Management.Automation.SwitchParameter, System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 + True WhatIf - System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Management.Automation.SwitchParameter, System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 + True Confirm - System.String[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Management.Automation.SwitchParameter, System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 + True From ac5b8d833391f98bd4fe6521c1757b3848311f9d Mon Sep 17 00:00:00 2001 From: Tome Tanasovski Date: Mon, 21 Apr 2014 15:27:26 -0400 Subject: [PATCH 05/10] Issue #17 - Rename the project to PshOdata --- Odata.psd1 => PshOdata.psd1 | Bin 5544 -> 5550 bytes Odata.psm1 => PshOdata.psm1 | 6 +-- tests/{Odata.tests.ps1 => PshOdata.tests.ps1} | 36 +++++++++--------- 3 files changed, 21 insertions(+), 21 deletions(-) rename Odata.psd1 => PshOdata.psd1 (98%) rename Odata.psm1 => PshOdata.psm1 (96%) rename tests/{Odata.tests.ps1 => PshOdata.tests.ps1} (75%) diff --git a/Odata.psd1 b/PshOdata.psd1 similarity index 98% rename from Odata.psd1 rename to PshOdata.psd1 index 2341abf37d3acb1911cf9edf4d08ba613d2833fd..c1e61a5b3c61fb0e44a01bcfe2104d609d8bb699 100644 GIT binary patch delta 20 bcmZ3Xy-s_>G)DFShGK>c2LH{|83jcEM;is@ delta 14 VcmZ3dy+V7#G)Bh!&2t$AMF1*w1lj-q diff --git a/Odata.psm1 b/PshOdata.psm1 similarity index 96% rename from Odata.psm1 rename to PshOdata.psm1 index fa7a5f1..b26e972 100644 --- a/Odata.psm1 +++ b/PshOdata.psm1 @@ -24,7 +24,7 @@ $rbacconfigtemplate = @' $paramignorelist = @('PipelineVariable','OutBuffer','OutVariable','WarningVariable','ErrorVariable','WarningAction', 'ErrorAction','Debug','Verbose') -function New-OdataClass { +function New-PshOdataClass { param( [Parameter(Mandatory=$true, Position=0)] [string] $Name, @@ -42,7 +42,7 @@ function New-OdataClass { } } -function Set-OdataMethod { +function Set-PshOdataMethod { param( [Parameter(Mandatory=$true, ValueFromPipeline=$true)] [PSObject[]] $InputObject, @@ -70,7 +70,7 @@ function Set-OdataMethod { } } -function New-OdataEndpoint { +function New-PshOdataEndpoint { param( [Parameter(Mandatory=$false, ValueFromPipeline=$true)] [PsObject[]] $OdataClasses, diff --git a/tests/Odata.tests.ps1 b/tests/PshOdata.tests.ps1 similarity index 75% rename from tests/Odata.tests.ps1 rename to tests/PshOdata.tests.ps1 index 53f3b95..368f012 100644 --- a/tests/Odata.tests.ps1 +++ b/tests/PshOdata.tests.ps1 @@ -1,10 +1,10 @@ $here = (Split-Path (Split-Path -Parent $MyInvocation.MyCommand.Path)) -Invoke-Expression (gc "$here\odata.psm1" |out-String) +Invoke-Expression (gc "$here\PshOdata.psm1" |out-String) -$class = New-OdataClass Process -PK ID -Properties 'Name','ID' +$class = New-PshOdataClass Process -PK ID -Properties 'Name','ID' -Describe "New-OdataClass" { +Describe "New-PshOdataClass" { It "Returns a psobject with the provided name" { $class.name | Should Be "Process" } @@ -14,17 +14,17 @@ Describe "New-OdataClass" { It "Returns a psobject with two properties" { $class.properties.count |Should Be 2 } - It "New-OdataClass with only one property should return a list with one element in it" { - (New-OdataClass TestClass -PK ID -Properties 'ID').properties.count |Should Be 1 + It "New-PshOdataClass with only one property should return a list with one element in it" { + (New-PshOdataClass TestClass -PK ID -Properties 'ID').properties.count |Should Be 1 } } -Describe "Add-OdataMethod" { +Describe "Add-PshOdataMethod" { It "Validate that optional parameters are optional" { - {$class |set-odatamethod -verb get -cmdlet get-process} |should not Throw + {$class |Set-PshOdataMethod -verb get -cmdlet get-process} |should not Throw } It "Creates a GET method" { - {$class |set-odatamethod -verb get -cmdlet get-process -Params Name, ID -FilterParams Name} |should not Throw + {$class |Set-PshOdataMethod -verb get -cmdlet get-process -Params Name, ID -FilterParams Name} |should not Throw } It "Sets the get property of the class" { $class.get |should not BeNullOrEmpty @@ -36,13 +36,13 @@ Describe "Add-OdataMethod" { $class.update|should BeNullOrEmpty } It "Creates a DELETE method" { - $class |set-odatamethod -verb delete -cmdlet stop-process -FilterParams ID,name -params ID,name + $class |Set-PshOdataMethod -verb delete -cmdlet stop-process -FilterParams ID,name -params ID,name } It "Fails if verb is not valid" { - {$class |set-odatamethod -verb blah -cmdlet dir -pk ID -Params Name, ID -FilterParams Name} |should Throw + {$class |Set-PshOdataMethod -verb blah -cmdlet dir -pk ID -Params Name, ID -FilterParams Name} |should Throw } It "Fails if cmdlet is not valid" { - {$class |set-odatamethod -verb get -cmdlet dir -pk ID -Params Name, ID -FilterParams Name} |should Throw + {$class |Set-PshOdataMethod -verb get -cmdlet dir -pk ID -Params Name, ID -FilterParams Name} |should Throw } } @@ -127,15 +127,15 @@ Describe "ConvertTo-ClassXML" { } } -Describe "New-OdataEndpoint" { - It "New-OdataEndpoint succeeds if the folder exists and the -Force switch is used" { - {$class |New-OdataEndpoint} |Should Not Throw +Describe "New-PshOdataEndpoint" { + It "New-PshOdataEndpoint succeeds if the folder exists and the -Force switch is used" { + {$class |New-PshOdataEndpoint} |Should Not Throw } - It "New-OdataEndpoint should fail if the folder exists" { - {$class |New-OdataEndpoint} |Should Throw + It "New-PshOdataEndpoint should fail if the folder exists" { + {$class |New-PshOdataEndpoint} |Should Throw } - It "New-OdataEndpoint succeeds if the folder exists and the -Force switch is used" { - {$class |New-OdataEndpoint -Force} |Should Not Throw + It "NewPshOdataEndpoint succeeds if the folder exists and the -Force switch is used" { + {$class |New-PshOdataEndpoint -Force} |Should Not Throw } It "Should create schema.mof" { join-path odata schema.mof |Should exist From 9e693cb17008a330357b06c90fa77c3c8b233b68 Mon Sep 17 00:00:00 2001 From: Tome Tanasovski Date: Thu, 24 Apr 2014 12:09:06 -0400 Subject: [PATCH 06/10] Issue #21 Tests should be usable via pester.bat or invoke-pester --- tests/PshOdata.tests.ps1 | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/tests/PshOdata.tests.ps1 b/tests/PshOdata.tests.ps1 index 368f012..0147607 100644 --- a/tests/PshOdata.tests.ps1 +++ b/tests/PshOdata.tests.ps1 @@ -1,6 +1,12 @@ -$here = (Split-Path (Split-Path -Parent $MyInvocation.MyCommand.Path)) +$here = '' +if ($MyInvocation.MyCommand.Path) { + $here = Split-Path $MyInvocation.MyCommand.Path +} else { + $here = $pwd -replace '^\S+::','' +} +$odatapath = join-path $here "odata" -Invoke-Expression (gc "$here\PshOdata.psm1" |out-String) +Invoke-Expression (gc "$here\..\PshOdata.psm1" |out-String) $class = New-PshOdataClass Process -PK ID -Properties 'Name','ID' @@ -120,7 +126,7 @@ Describe "ConvertTo-ResourceXML" { } } -$validatexml = [IO.file]::ReadAllText((join-path tests validate_schema.xml)) +$validatexml = [IO.file]::ReadAllText((join-path $here validate_schema.xml)) Describe "ConvertTo-ClassXML" { It "Converts a class to the text needed in the class section of the schema.xml" { $class |ConvertTo-ClassXML |Should be $validatexml @@ -129,25 +135,25 @@ Describe "ConvertTo-ClassXML" { Describe "New-PshOdataEndpoint" { It "New-PshOdataEndpoint succeeds if the folder exists and the -Force switch is used" { - {$class |New-PshOdataEndpoint} |Should Not Throw + {$class |New-PshOdataEndpoint -Path $odatapath} |Should Not Throw } It "New-PshOdataEndpoint should fail if the folder exists" { - {$class |New-PshOdataEndpoint} |Should Throw + {$class |New-PshOdataEndpoint -Path $odatapath} |Should Throw } It "NewPshOdataEndpoint succeeds if the folder exists and the -Force switch is used" { - {$class |New-PshOdataEndpoint -Force} |Should Not Throw + {$class |New-PshOdataEndpoint -Path $odatapath -Force} |Should Not Throw } It "Should create schema.mof" { - join-path odata schema.mof |Should exist + join-path $odatapath schema.mof |Should exist } It "Should create schema.xml" { - join-path odata schema.xml |Should exist + join-path $odatapath schema.xml |Should exist } It "Should create RbacConfiguration.xml" { - join-path odata RbacConfiguration.xml |Should exist + join-path $odatapath RbacConfiguration.xml |Should exist } It "Validate data in RbacConfiguration.xml" { - [IO.file]::ReadAllText((join-path odata RbacConfiguration.xml)) |Should be @" + [IO.file]::ReadAllText((join-path $odatapath RbacConfiguration.xml)) |Should be @" @@ -161,5 +167,5 @@ Describe "New-PshOdataEndpoint" { } # cleanup the directory created during the tests -rm (join-path $here odata) -recurse +rm $odatapath -recurse From ea13ca3d96d9883e21f2655f48a2afb3961c9a62 Mon Sep 17 00:00:00 2001 From: Tome Tanasovski Date: Mon, 28 Apr 2014 16:53:52 -0400 Subject: [PATCH 07/10] Issue #20 Parameter names are case sensitive in FieldParameterMap --- PshOdata.psm1 | 17 ++++++++++++++++- tests/PshOdata.tests.ps1 | 4 ++-- tests/validate_schema.xml | 8 ++++---- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/PshOdata.psm1 b/PshOdata.psm1 index b26e972..6829cee 100644 --- a/PshOdata.psm1 +++ b/PshOdata.psm1 @@ -165,13 +165,28 @@ function ConvertTo-ClassXML{ $text += $paramtext + " "*10 + "`r`n" } + $paramnames = (get-command $class.($verb).Cmdlet |select -ExpandProperty Parameters).keys # Add Filter parameters/FieldParameterMap section if ($class.($verb).FilterParameters) { $paramtext = " "*10 + "`r`n" foreach ($parameter in ($class.($verb).FilterParameters)) { + $targetparameter = $parameter + # FieldParameters are case sensitive on the target parameter + if ($paramnames -cnotcontains $parameter) { + if ($paramnames -contains $parameter) { + foreach ($name in $paramnames) { + if ($parameter -eq $name) { + # Set it blank first otherwise it won't take the case change + $targetparameter = $name + } + } + } else { + throw "{0} parameter does not exist in {1}" -f $parameter, $section, $class.($verb).Cmdlet + } + } $paramtext += " "*12 + "`r`n" $paramtext += " "*14 + "{0}`r`n" -f $parameter - $paramtext += " "*14 + "{0}`r`n" -f $parameter + $paramtext += " "*14 + "{0}`r`n" -f $targetparameter $paramtext += " "*12 + "`r`n" } $paramtext += " "*10 + "`r`n" diff --git a/tests/PshOdata.tests.ps1 b/tests/PshOdata.tests.ps1 index 0147607..3ae3b96 100644 --- a/tests/PshOdata.tests.ps1 +++ b/tests/PshOdata.tests.ps1 @@ -42,7 +42,7 @@ Describe "Add-PshOdataMethod" { $class.update|should BeNullOrEmpty } It "Creates a DELETE method" { - $class |Set-PshOdataMethod -verb delete -cmdlet stop-process -FilterParams ID,name -params ID,name + $class |Set-PshOdataMethod -verb delete -cmdlet stop-process -FilterParams ID,Name -params ID,Name } It "Fails if verb is not valid" { {$class |Set-PshOdataMethod -verb blah -cmdlet dir -pk ID -Params Name, ID -FilterParams Name} |should Throw @@ -129,7 +129,7 @@ Describe "ConvertTo-ResourceXML" { $validatexml = [IO.file]::ReadAllText((join-path $here validate_schema.xml)) Describe "ConvertTo-ClassXML" { It "Converts a class to the text needed in the class section of the schema.xml" { - $class |ConvertTo-ClassXML |Should be $validatexml + $class |ConvertTo-ClassXML |Should BeExactly $validatexml } } diff --git a/tests/validate_schema.xml b/tests/validate_schema.xml index 0937d1d..cfb1d99 100644 --- a/tests/validate_schema.xml +++ b/tests/validate_schema.xml @@ -126,16 +126,16 @@ stop-process ID - name + Name ID - ID + Id - name - name + Name + Name From 0c7139df5d4f530cf0eb5fb73d17cd889399d2d6 Mon Sep 17 00:00:00 2001 From: Tome Tanasovski Date: Mon, 28 Apr 2014 18:58:32 -0400 Subject: [PATCH 08/10] Issue #16 - Resolve or understand issues with Delete --- PshOdata.psm1 | 8 ++++++++ tests/PshOdata.tests.ps1 | 8 +++++++- tests/validate_schema.xml | 8 -------- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/PshOdata.psm1 b/PshOdata.psm1 index 6829cee..18b9437 100644 --- a/PshOdata.psm1 +++ b/PshOdata.psm1 @@ -60,6 +60,14 @@ function Set-PshOdataMethod { [string[]] $FilterParameters ) PROCESS { + if ($verb -eq 'delete') { + # Delete only appears to work with the pk in the fieldparameterset. + # It actually doesn't work with parameters at all + if ($Parameters.count -gt 0 -or $FilterParameters.count -gt 1 -or $FilterParameters[0] -ne $InputObject.pk) { + throw "DELETE methods can only use the primary key as a FieldParameter and they cannot use parameters. + Try Set-PshOdataMethod -verb DELETE -FilterParameters $($InputObject.pk)" + } + } $method = new-object psobject -Property @{ Cmdlet = $cmdlet Module = 'c:\windows\system32\WindowsPowerShell\v1.0\Modules\{0}' -f (get-command $Cmdlet).Modulename diff --git a/tests/PshOdata.tests.ps1 b/tests/PshOdata.tests.ps1 index 3ae3b96..0a0c2e9 100644 --- a/tests/PshOdata.tests.ps1 +++ b/tests/PshOdata.tests.ps1 @@ -42,8 +42,14 @@ Describe "Add-PshOdataMethod" { $class.update|should BeNullOrEmpty } It "Creates a DELETE method" { - $class |Set-PshOdataMethod -verb delete -cmdlet stop-process -FilterParams ID,Name -params ID,Name + {$class |Set-PshOdataMethod -verb delete -cmdlet stop-process -FilterParams ID} |should not Throw } + It "Fails if the DELETE method has a FieldParam that is not the pk" { + {$class |Set-PshOdataMethod -verb delete -cmdlet stop-process -FilterParams Name} |Should Throw + } + It "Fails if the DELETE method has a value for the params argument" { + {$class |Set-PshOdataMethod -verb delete -cmdlet stop-process -FilterParams ID -params ID,Name} |Should Throw + } It "Fails if verb is not valid" { {$class |Set-PshOdataMethod -verb blah -cmdlet dir -pk ID -Params Name, ID -FilterParams Name} |should Throw } diff --git a/tests/validate_schema.xml b/tests/validate_schema.xml index cfb1d99..2d76b7a 100644 --- a/tests/validate_schema.xml +++ b/tests/validate_schema.xml @@ -124,19 +124,11 @@ stop-process - - ID - Name - ID Id - - Name - Name - From e213c35b9c0f50ea188b3f7c2bb9b78d733d1284 Mon Sep 17 00:00:00 2001 From: Tome Tanasovski Date: Mon, 28 Apr 2014 19:22:23 -0400 Subject: [PATCH 09/10] Adding MIT license to the project --- license | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 license diff --git a/license b/license new file mode 100644 index 0000000..6d84f0b --- /dev/null +++ b/license @@ -0,0 +1,8 @@ +Copyright (C) 2014 Tome Tanasovski + +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. + From 18595bc753d50749e9e7c31c225b121d5447bdb3 Mon Sep 17 00:00:00 2001 From: Tome Tanasovski Date: Tue, 29 Apr 2014 10:14:18 -0400 Subject: [PATCH 10/10] Issue #12 - Create a beginning set of documentation. Help added to the exported functions and README.md created. --- PshOdata.psm1 | 181 +++++++++++++++++++++++++++++++++++++++++++++++++- README.md | 60 +++++++++++++++++ 2 files changed, 239 insertions(+), 2 deletions(-) create mode 100644 README.md diff --git a/PshOdata.psm1 b/PshOdata.psm1 index 18b9437..6faeec5 100644 --- a/PshOdata.psm1 +++ b/PshOdata.psm1 @@ -25,6 +25,46 @@ $paramignorelist = @('PipelineVariable','OutBuffer','OutVariable','WarningVariab 'ErrorAction','Debug','Verbose') function New-PshOdataClass { +<# + .Synopsis + Creates a PowerShell representation of an Odata class + + .Description + In order to create an odata endpoint, you must first create a class, add GET, UPDATE, CREATE, and/or DELETE + methods for the class, and finally generate the odata files by creating the odata endpoint. + + New-PshOdataClass is used to create the odata class. It specifies what properties are available. This acts + as a sort of Select-Object for the GET method that you will create for the class. + + .Parameter Name + The name of the class. This will be the name used in your odata url, e.g., http://server/odata/classname + + .Parameter PK + Every odata endpoint must have a primary key. This must be a unique identifier for the class. If the cmdlet + you are using does not have a unique value, you will need to wrap the cmdlet in another cmdlet that will add + a primary key before you can create a get method for the class. + + .Parameter Properties + This is the list of properties that will be available to the class. This can be thought of as a Select-Object + after your get- cmdlet. Regardless of what your cmdlet returns, only the properties listed will be visible + when viewing the objects for the class. + + .Inputs + Strings + + .Outputs + PSObject + + .Example + The following is a class that can be used to represent a ProcessInfo object. This class may be used with + a GET method that is returned by the Get-Process cmdlet. + + New-PshOdataClass Process -PK ID -Properties 'Name','ID' + + .LINK + https://github.com/toenuff/PshOdata/ + +#> param( [Parameter(Mandatory=$true, Position=0)] [string] $Name, @@ -43,6 +83,77 @@ function New-PshOdataClass { } function Set-PshOdataMethod { +<# + .Synopsis + This cmdlet adds a GET, DELETE, UPDATE, or CREATE method to the class + + .Description + This cmdlet binds one of the HTTP verbs, i.e., GET, DELETE, UPDATE, or CREATE, to a cmdlet that is installed on the + local system. The cmdlet must be in a module in order for it to work. The method will be added to a PshOdataClass + PSObject that is created by New-PshOdataClass. + + .Parameter InputObject + This is the class that you are setting the method for. This is generally the object returned from New-PshOdataClass + + .Parameter Verb + This is the HTTP verb for the method you are setting. It must be either GET, DELETE, UPDATE, or CREATE. + + Currently only GET and DELETE have been proven to work + + .Parameter Params + This is only supported with the Get method. It will allow you to pass a specific parameter to a cmdlet via the + following syntax in the url: + + http://servername/odata/classname?paramname=value + + .Parameter FilterParams + This is a special parameter that can be used with odata filters. Filtering can be done with any property of the + Odata class. However, if you use a filter parameter, it will ensure that the filter is applied by calling the + associated cmdlet with the parametername specified. This only works with the GET method. + + This will allow you to use the following url: + + http://servername/odata/classname?$filter=(FilterParam eq 'value') + This will call + cmdletname -FilterParam value + + Delete methods should have a FilterParam for the primary key specified in order for Delete to work. If your + cmdlet does not take the PK as a property, you will need to wrap the function in another cmdlet that will accept + the PK. + + .Parameter Cmdlet + This is the cmdlet that the method will invoke under the covers. The cmdlet must be in a module in order for it to + work. + + .Inputs + PSObject + + .Outputs + PSObject + + .Example + The following will add a get method that uses get-process. It will allow name and ID parameters, and it will + allow Name to be used as a parameter if a filter is specified in the URL. + + $class |Set-PshOdataMethod -verb get -cmdlet get-process -Params Name, ID -FilterParams Name + + The above will allow the following urls: + http://servername/odata/Process + http://servername/odata/Process?Name=notepad + http://servername/odata/Process?ID=3212 + + .Example + The following will create a delete method that runs stop-process: + + $class |Set-PshOdataMethod -verb delete -cmdlet stop-process -FilterParams ID + + The above will allow the delete verb to be passed to the following URL: + http://servername/odata/Process('3333') + + .LINK + https://github.com/toenuff/PshOdata/ + +#> param( [Parameter(Mandatory=$true, ValueFromPipeline=$true)] [PSObject[]] $InputObject, @@ -79,9 +190,75 @@ function Set-PshOdataMethod { } function New-PshOdataEndpoint { +<# + .Synopsis + Creates an odata endpoint from a collection of defined Odata class objects with methods + + .Description + This cmdlet is used in conjunction with New-PshOdataClass and Set-PshOdataMethod. When New-PshOdataEndpoint is called, + the following three files are created: + + Schema.mof - a document that describes the properties and PK for the classes in the endpoint. + Schema.xml - a document that describes details about the methods and underlying PowerShell cmdlets that will be called through the endpoint. + RbacConfiguration.xml - a document that describes which modules to load. This set of cmdlets assumes that the underlying modules are + located in c:\windows\system32\WindowsPowerShell\modules. + + These files need to be manually copied to the folder of an IIS server that is configured with an application that is using the Odata IIS extensions. + An IISreset is also required. + + .Parameter Path + The folder where you would like to save the schema.mof, schema.xml, and RbacConfiguration.xml files too. This defaults to an odata folder in + the current working directory + + .Parameter PshOdataClasses + A collection of PshOdata classes with methods that are set for the classes. This generally comes from the output of New-PshOdataClass and + Set-PshOdataMethod. + + .Parameter Force + This is used to overwrite the output files if they already exist. + + .Inputs + PSObject + + .Outputs + Three files: Schema.mof, Schema.xml, and RbaConfiguration + + .Example + $class = New-PshOdataClass Process -PK ID -Properties 'Name','ID' + $class |Set-PshOdataMethod -verb get -cmdlet get-process -Params Name, ID -FilterParams Name + $class |Set-PshOdataMethod -verb delete -cmdlet stop-process -FilterParams ID + $class | New-PshOdataEndpoint + + The above will create the files required to allow GET and SET http methods to a url like this: + http://server/odata/Process + http://server/odata/Process('3333') # 3333 is the ID of the process you would like to retrieve. This is the only url that works for delete. + http://server/odata/Process?name=notepad + http://server/odata/Process?$filter=(name eq 'notepad') + http://server/odata/Process?$format=application/json;odata=verbose #Used to render JSON instead of XML + + The endpoint will return Process objects that contain Name and ID Properties that are taken from Get-Process. It will also allow the DELETE + method to call Stop-Process when the PK is used. + + .Example + The following creates the files required for an Odata Endpoint that serves Process and Service objects that are returned from Get-Process and Get-Service + $classes = @() + $classes += New-PshOdataClass Process -PK ID -Properties 'Name', 'ID' |Set-PshOdataMethod -verb get -cmdlet get-process -Params Name, ID -FilterParams Name + $classes += New-PshOdataClass Service -PK Name -Properties 'Status', 'Name', 'Displayname' |Set-PshOdataMethod -verb get -cmdlet get-Service -Params Name -FilterParams Name + $classes |New-PshOdataEndpoint + + .Example + The following script will create the files required for an Odata endpoint directly into c:\inetpub\wwwroot\odata. If the files exist already, + they will be overwritten. + + $class |New-PshOdataEndpoint -Path c:\inetpub\wwwroot\odata -Force + + .LINK + https://github.com/toenuff/PshOdata/ + +#> param( [Parameter(Mandatory=$false, ValueFromPipeline=$true)] - [PsObject[]] $OdataClasses, + [PsObject[]] $PshOdataClasses, [Parameter(Mandatory=$false, position=0)] [string]$Path = "odata", [Switch]$Force @@ -96,7 +273,7 @@ function New-PshOdataEndpoint { $classes = @() } PROCESS { - $classes += $OdataClasses + $classes += $PshOdataClasses } END { $mof = "" diff --git a/README.md b/README.md new file mode 100644 index 0000000..5ede891 --- /dev/null +++ b/README.md @@ -0,0 +1,60 @@ +# PshOdata Module + +2008R2 and 2012 versions of Windows contain a feature called IIS Odata Extensions. An IIS application that uses the extensions can be configured to create a RESTful web service that will run PowerShell cmdlets and return the objects as either JSON or XML. The PshOdata Module makes it easy to generate the files used to create these endpoints. + +## Example Usage +> $class |Set-PshOdataMethod -verb get -cmdlet get-process -Params Name, ID -FilterParams Name +> $class |Set-PshOdataMethod -verb delete -cmdlet stop-process -FilterParams ID +> $class | New-PshOdataEndpoint + +The above will create the files required to allow GET and SET http methods to a url like this: +* http://server/odata/Process +* http://server/odata/Process('3333') # 3333 is the ID of the process you would like to retrieve. This is the only url that works for delete. +* http://server/odata/Process?name=notepad +* http://server/odata/Process?$filter=(name eq 'notepad') +* http://server/odata/Process?$format=application/json;odata=verbose #Used to render JSON instead of XML + +The endpoint will return Process objects that contain Name and ID Properties that are taken from Get-Process. It will also allow the DELETE +method to call Stop-Process when the PK is used. + +## Files Generated + +The New-PshOdataEndpoint function will create a set of files in an odata folder within the current working directory by default. + +The following files are generated: +* Schema.mof - a document that describes the properties and PK for the classes in the endpoint. +* Schema.xml - a document that describes details about the methods and underlying PowerShell cmdlets that will be called through the endpoint. +* RbacConfiguration.xml - a document that describes which modules to load. This set of cmdlets assumes that the underlying modules are located in c:\windows\system32\WindowsPowerShell\modules. + +## Installation of the files + +Currently, we do not have a method to create the IIS portion of the Odata extensions. We plan on solving this with a function soon. However, in the meantime, you can use the OdataSchemaDesigner in order to have your first endpoint created, and then you can use these cmdlets to generate the files you need for your Odata service. + +The following steps must be performed on Windows Server 2012 box that does NOT have R2. + +1. Add-WindowsFeature ManagementOdata # Install the odata extensions +1. Install Visual Studio Isolated Shell - http://www.microsoft.com/en-us/download/details.aspx?id=1366 +1. Install the odata extension isolated installer - http://archive.msdn.microsoft.com/mgmtODataWebServ/Release/ProjectReleases.aspx?ReleaseId=5877 +1. Launch the Management Odata Schema Designer from the start screen + 1. File-> New File -> Management Odata Model + 1. Right-Click and select Import Cmdlets + 1. Local Computer -> Next + 1. Installed Windows PowerShell Modules -> Microsoft.PowerShell.Management + 1. Choose Service -> Next + 1. Uncheck CREATE and UPDATE. Only Get should be selected. Next. + 1. Next + 1. Choose any key and click Next. + 1. Next + 1. Finish + 1. Right click in the designer and choose Publish Odata Endpoint + 1. Select the local computername and fill out a username and password. Choose a name for the site (odata is a good choice). Finally select a port number and then click Publish. + +Once the IIS server has the site created. You can use the cmdlets in this module to generate the schema.xml, schema.mof, and rbacconfiguration.xml files. Copy these files into the application you created (c:\inetpub\wwwroot\odata). Perform an IISReset. Enjoy your web service. + +## Notes + +* Currently only GET and DELETE is supported +* Use *Get-Command -Module PshOdata* in order to see the cmdlets in the module +* Use *Get-Help cmdletname -full* in order to see the full set of documenation along with examples you can try +* Odata classes require a primary key. This needs to be a unique value for each object returned. If one does not exist for the data you are retrieving from PowerShell, you will need to create a wrapper function in a new module that calls your function and creates a primary key. You can then create a method based on this new cmdlet. +* When creating a DELETE method, you may only use the PK as a parameter. Your delete cmdlet must support this.