{"id":335,"date":"2011-07-12T01:00:00","date_gmt":"2011-07-12T10:00:00","guid":{"rendered":"http:\/\/www.cloudidentity.com\/blog\/2011\/07\/12\/updated-windows-azure-access-control-service-cmdlets-modules-continuation-and-backuprestore\/"},"modified":"2013-03-14T20:31:50","modified_gmt":"2013-03-15T05:31:50","slug":"updated-windows-azure-access-control-service-cmdlets-modules-continuation-and-backup-restore","status":"publish","type":"post","link":"https:\/\/www.cloudidentity.com\/blog\/2011\/07\/12\/updated-windows-azure-access-control-service-cmdlets-modules-continuation-and-backup-restore\/","title":{"rendered":"Updated Windows Azure Access Control Service Cmdlets: Modules, Continuation and Backup\/Restore!"},"content":{"rendered":"<p><a href=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2011\/07\/3051.powershell_5F00_554C330C.png\"><img loading=\"lazy\" decoding=\"async\" title=\"powershell\" border=\"0\" alt=\"powershell\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2011\/07\/3051.powershell_5F00_554C330C.png\" width=\"300\" height=\"150\" \/><\/a><\/p>\n<p>As promised yesterday, here there\u2019s one of the deliverables I mentioned. About one month ago we published the first release of <a href=\"http:\/\/bit.ly\/kF9ksY\">a set of PowerShell cmdlets for ACS<\/a>: wrappers for the ACS management APIs, which allow you to easily script tasks such as wiping a namespace, <a href=\"http:\/\/bit.ly\/j28pYy\">adding an OpenID provider<\/a>, automating often-used provisioning flows and much more.     <br \/>The cmdlets were sample quality, but that didn\u2019t prevent you from jumping on it with enthusiasm and give us a lot of great feedback: I credit especially the hosts and the audience of the <a href=\"http:\/\/bit.ly\/kZPqcu\">Powerscripting podcast<\/a>, who were so kind to have me on one episode and provide passionate commentary on what we had to improve.<\/p>\n<p>Well, I am happy to announce that many of the requested improvements are here! If you head to <a title=\"http:\/\/wappowershell.codeplex.com\/\" href=\"http:\/\/bit.ly\/nvcW0b\">http:\/\/wappowershell.codeplex.com\/<\/a>, you\u2019ll find <a href=\"http:\/\/bit.ly\/llnWl7\">a new drop of the ACS cmdlets waiting for you<\/a>. It\u2019s the file <a href=\"http:\/\/bit.ly\/llnWl7\">ACSCmdlets20110711.exe<\/a>, for good measure I took down the old one.<\/p>\n<p>Make no mistake: this is still sample quality, but we added some features which will make those even more useful. Here there\u2019s a list:<\/p>\n<h3>Snap-ins are out of fashion? Try our Modules <\/h3>\n<p><a href=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2011\/07\/0334.image_5F00_0B030BCD.png\"><img loading=\"lazy\" decoding=\"async\" style=\"border-right-width: 0px;padding-left: 0px;padding-right: 0px;border-top-width: 0px;border-bottom-width: 0px;border-left-width: 0px;padding-top: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2011\/07\/0334.image_5F00_0B030BCD.png\" width=\"400\" height=\"164\" \/><\/a><\/p>\n<p>Hal and Jonathan had no doubt: our choice of delivering the cmdlets via snap-in was anachronistic, and we absolutely had to move things in a module.    <br \/>We decided to offer that as an option at install time: now when you unpack the sample you will be prompted to choose if you want to use a module or a snap-in, perhaps if you are running an older version of PowerShell.<\/p>\n<h3>No more \u201cplurals\u201d <\/h3>\n<p>Another thing the <a href=\"http:\/\/bit.ly\/kZPqcu\">Powerscripting<\/a> crew was adamant about was the presence of one \u201csingular\u201d and one \u201cplural\u201d commands for every entity (ie Get-Rule and Get-Rule<strong><u><em>s<\/em><\/u><\/strong>). As it turns out, the common practice in PowerShell is to have just the \u201csingular\u201d version and cleverly use the parameters (or lack thereof) to let PowerShell figure out the multiplicity of the result. That\u2019s exactly what we\u2019ve done! In our case, it\u2019s the presence of the \u2013Name parameter which determines if we are interested in one specific entity or a collection. The snippet below, helpfully provided by Lito from our friends at Southworks, hopefully gets the point across:<\/p>\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"929\">\n<p><font face=\"Courier New\"><strong># retrieve the full list of Identity Providers<\/strong><\/font><\/p>\n<p><font face=\"Courier New\">&gt; Get-IdentityProvider \u2013Namespace $yourNamespace \u2013ManagementKey $yourManagementKey<\/font><\/p>\n<p><font face=\"Courier New\"><strong># retrieve a single Identity Provider<\/strong><\/font><\/p>\n<p><font face=\"Courier New\">&gt; Get-IdentityProvider \u2013Namespace $yourNamespace \u2013ManagementKey $yourManagementKey <strong>\u2013Name \u201cWindows Live ID\u201d<\/strong><\/font><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>&#160;<\/h3>\n<h3>Your list exceeds the 100 entries? Try our new Get API<\/h3>\n<p>The feedback for this feature came from a colleague, who was very happy of the cmdlets until he discovered that he never managed to get result sets with more than 100 elements (he had the need to get MANY MORE). The ACS management API indeed cap their result to 100 elements, but as good OData citizens they also support continuation tokens. In the first release we didn\u2019t handle those hence you were limited to what you get in the first shot to the API. This release does handle continuation tokens. It does so transparently, without surfacing the continuation token itself and forcing you to make multiple calls: we retrieve all the results for you, and if you want to break things down you can use the tools that PowerShell offers (like the classic <font face=\"Courier New\">| more<\/font>).<\/p>\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"929\">\n<p><font face=\"Courier New\"><strong># retrieve the full list of rules from a RuleGroup<\/strong><\/font><\/p>\n<p><font face=\"Courier New\">&gt; Get-Rule -GroupName $ruleGroup -Namespace $namespace -ManagementKey $managementKey | more<\/font><\/p>\n<p><font face=\"Courier New\">&#160;<\/font><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>Add-, Get- and Remove- cmdlets for SeviceIdentities and ServiceIdentityKeys<\/h3>\n<p>You asked to be able to handle ServiceIdentity and associated keys: we obliged. Just make sure that you don\u2019t fall in the fallacy of misusing them to use ACS as an identity provider, instead of unleashing its true federation provider potential. <\/p>\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"929\">\n<p><font face=\"Courier New\">&gt; Add-ServiceIdentity -ServiceIdentity &lt;ServiceIdentity&gt;<\/font><\/p>\n<p><font face=\"Courier New\">&gt; Add-ServiceIdentity \u2013Name &lt;String&gt; \u2013Description &lt;string&gt;<\/font><\/p>\n<p><font face=\"Courier New\">&gt; Get-ServiceIdentity [-Name &lt;string&gt;]<\/font><\/p>\n<p><font face=\"Courier New\">&gt; Remove-ServiceIdentity -Name &lt;string&gt;<\/font><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"929\">\n<p><font face=\"Courier New\">&gt; Add-ServiceIdentityKey -ServiceIdentityKey &lt;ServiceIdentityKey&gt; -ServiceIdentityName &lt;String&gt; <\/font><\/p>\n<p><font face=\"Courier New\">&gt; Add-ServiceIdentityKey -Key &lt;String&gt; [-EffectiveDate &lt;DateTime&gt;] [-ExpirationDate &lt;DateTime&gt;] -ServiceIdentityName &lt;String&gt; [-Name &lt;String&gt;]<\/font><\/p>\n<p><font face=\"Courier New\">&gt; Add-ServiceIdentityKey -Password &lt;String&gt; [-EffectiveDate &lt;DateTime&gt;] [-ExpirationDate &lt;DateTime&gt;] -ServiceIdentityName &lt;String&gt; [-Name &lt;String&gt;]<\/font><\/p>\n<p><font face=\"Courier New\">&gt; Add-ServiceIdentityKey -Certificate &lt;X509Certificate2&gt; -ServiceIdentityName &lt;String&gt; [-Name &lt;String&gt;]<\/font><\/p>\n<p><font face=\"Courier New\">&gt; Get-ServiceIdentityKey [-Id &lt;Int64&gt;] [-ServiceIdentityName &lt;String&gt;]<\/font><\/p>\n<p><font face=\"Courier New\">&gt; Remove-ServiceIdentityKey -Id &lt;Int64&gt;<\/font><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>Add- cmdlets now can take an entire object as a parameter<\/h3>\n<p>We are getting closer to the entr\u00e9e of this release, and the update discussed here is what makes it at all possible.<\/p>\n<p>In the former release every Add- cmdlets took the attributes constituting the entity to be created as individual parameters. That worked, especially thanks to the fact that we picked meaningful defaults should the cmdlet be called with some omitted parameter. However it made especially hard to concatenate Add- with other commands, like a Get-, without adding complicated parsing logic that would break down the object coming from Get- in the individual parameters that Add- required. Well, get this: now all the Add- cmdlets accept also entire objects as parameters, making possible some interesting tricks like the one below:<\/p>\n<p><font face=\"Courier New\"><strong># retrieve an Identity Provider from one namespace and add it to another one<\/strong><\/font><\/p>\n<p><font face=\"Courier New\">&gt; $RP = Get-RelyingParty -Name \u201cName Here\u201d -MgmtToken $sourceNamespaceToken<\/font><\/p>\n<p><font face=\"Courier New\">&gt; Add-RelyingParty -RelyingParty $RP -MgmtToken $targetNamespaceToken<\/font><\/p>\n<p>You see where I am getting at here, right?<\/p>\n<h3>Backup and restore an ACS namespace<\/h3>\n<p>Enabling backup and restore was one of the main reasons for which we thought of creating a PowerShell cmdlets sample in the first place: with this release we are finally able to demonstrate that in a reasonably short and easy to read script. <\/p>\n<p>In the cmdlets installation folder, sub-folder sampleScript\/, you\u2019ll find a series of sample scripts which can be used for save, restore or even transfer an entire namespace at once. Let\u2019s play!&#160; Open a PowerShell prompt and navigate to the sampleScript folder. Pick an ACS namespace you like, retrieve the management key and enter something to the effect of<\/p>\n<p><font face=\"Courier New\">.ExportNamespace.ps1 &quot;myNamespace&quot; &quot;8m+1[.key.]mUE=&quot; &quot;c:tempmyNamespace.acsns&quot;<\/font><\/p>\n<p>You\u2019ll get the following output:<\/p>\n<p><font face=\"Courier New\">Importing AcsManagement Module&#8230;     <br \/>Getting all the Identity Providers from myNamespace namespace&#8230;      <br \/>Getting all the Relying Parties from myNamespace namespace&#8230;      <br \/>Getting all the Rule Groups from myNamespace namespace&#8230;      <br \/>Getting all the Service Keys from myNamespace namespace&#8230;      <br \/>Getting all the Service Identities from myNamespace namespace&#8230;      <br \/>Serializing all the information in myNamespace namespace to the c:tempmyNamespace.acsns file&#8230;<\/font><\/p>\n<p><font face=\"Courier New\">Done<\/font><\/p>\n<p>Looks pretty simple! Let\u2019s see what have we got in myNamespace.acsns. The namespace I used is pretty rich, resulting in a 32K file, hence dumping it here would not make a lot of sense. However take a look of the screenshot of the file as shown by XML Notepad:<\/p>\n<p><a href=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2011\/07\/2475.image_5F00_70566FB3.png\"><img loading=\"lazy\" decoding=\"async\" style=\"border-bottom: 0px;border-left: 0px;margin: 0px;padding-left: 0px;padding-right: 0px;border-top: 0px;border-right: 0px;padding-top: 0px\" title=\"image\" border=\"0\" alt=\"image\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2011\/07\/2475.image_5F00_70566FB3.png\" width=\"400\" height=\"544\" \/><\/a><\/p>\n<p>Yessirs, that is an XML representation of your namespace! The script that generated this file is surprisingly simple and readable:<\/p>\n<p><font face=\"Courier New\">Param($sourceNamespace = &quot;[your namespace]&quot;,     <br \/>&#160;&#160;&#160;&#160;&#160; $sourceManagementKey = &quot;[your namespace management key]&quot;,      <br \/>&#160;&#160;&#160;&#160;&#160; [string]$fileToExport = &quot;[path to output file]&quot;)&#160; <\/font><\/p>\n<p><font face=\"Courier New\">function Get-ScriptDirectory     <br \/>{      <br \/>&#160;&#160;&#160; $Invocation = (Get-Variable MyInvocation -Scope 1).Value      <br \/>&#160;&#160;&#160; Split-Path $Invocation.MyCommand.Path      <br \/>}<\/font><\/p>\n<p><font face=\"Courier New\">$scriptDirectory = Get-ScriptDirectory     <br \/>Set-Location $scriptDirectory<\/font><\/p>\n<p><font face=\"Courier New\">.AddSnapInAndModule.ps1<\/font><\/p>\n<p><font face=\"Courier New\">$sourceToken = Get-AcsManagementToken -Namespace $sourceNamespace -ManagementKey $sourceManagementKey     <br \/>$acsNamespaceInfo = New-Object Microsoft.Samples.DPE.ACS.ServiceManagementTools.PowerShell.Model.ServiceNamespace<\/font><\/p>\n<p><font face=\"Courier New\">&quot;Getting all the Identity Providers from $sourceNamespace namespace&#8230;&quot;     <br \/>$acsNamespaceInfo.IdentityProviders = Get-IdentityProvider -MgmtToken $sourceToken<\/font><\/p>\n<p><font face=\"Courier New\">&quot;Getting all the Relying Parties from $sourceNamespace namespace&#8230;&quot;     <br \/>$acsNamespaceInfo.RelyingParties = @()      <br \/>foreach ($s in Get-RelyingParty -MgmtToken $sourceToken)      <br \/>{      <br \/>&#160;&#160;&#160; $acsNamespaceInfo.RelyingParties += @(Get-RelyingParty -MgmtToken $sourceToken -Name $s.Name)      <br \/>}<\/font><\/p>\n<p><font face=\"Courier New\">&quot;Getting all the Rule Groups from $sourceNamespace namespace&#8230;&quot;     <br \/>$acsNamespaceInfo.RuleGroups = @()      <br \/>foreach ($s in Get-RuleGroup -MgmtToken $sourceToken)      <br \/>{      <br \/>&#160;&#160;&#160; $acsNamespaceInfo.RuleGroups += @(Get-RuleGroup -MgmtToken $sourceToken -Name $s.Name)      <br \/>}<\/font><\/p>\n<p><font face=\"Courier New\">&quot;Getting all the Service Keys from $sourceNamespace namespace&#8230;&quot;     <br \/>$acsNamespaceInfo.ServiceKeys = Get-ServiceKey -MgmtToken $sourceToken<\/font><\/p>\n<p><font face=\"Courier New\">&quot;Getting all the Service Identities from $sourceNamespace namespace&#8230;&quot;     <br \/>$acsNamespaceInfo.ServiceIdentities = Get-ServiceIdentity -MgmtToken $sourceToken<\/font><\/p>\n<p><font face=\"Courier New\">&quot;Serializing all the information in $sourceNamespace namespace to the $fileToExport file&#8230;&quot;     <br \/>if (! [System.IO.Path]::IsPathRooted(&quot;$fileToExport&quot;))      <br \/>{      <br \/>&#160;&#160;&#160; $fileToExport = Join-Path &quot;$scriptDirectory&quot; &quot;$fileToExport&quot;      <br \/>}      <br \/>$acsNamespaceInfo.Serialize($fileToExport)<\/font><\/p>\n<p><font face=\"Courier New\">&quot;&quot;     <br \/>&quot;Done&quot;<\/font><\/p>\n<p>In fact, there is nothing difficult about the above script: it\u2019s more or less the same foreach applied in turn to IPs, RPs, rule groups &amp; rules, service identities and keys.   <br \/>Now that you have all your namespace in file you can restore it in its entirety via ImportNamespace.ps1. In fact, nothing prevents you from applying those settings even to a different ACS namespace! The CloneNamespace.ps1 demonstrates exactly that scenario.<\/p>\n<p>Well, that\u2019s it! <a href=\"http:\/\/bit.ly\/llnWl7\">Play with the cmdlets<\/a> and let us know what you like, what you dislike and what you\u2019d like to see: I\u2019ll make sure to pass the feedback appropriately. As you know by now, I moved to the product team I won\u2019t be driving the next release of the ACS cmdlets; in fact, without the kind help of <a href=\"http:\/\/www.wadewegner.com\/\">Wade<\/a> who took care of some last minute logistic details even this release would not have been in your hands now: thanks <a href=\"http:\/\/www.wadewegner.com\/\">Wade<\/a>!<\/p>\n<p><em>And since we are on the thanks section, I wanted to take this chance to express my gratitude to the good folks at <a href=\"http:\/\/www.southworks.net\/\">Southworks<\/a>, with whom I worked very closely for the last few years, and to whom I owe my current caramel addiction (dulche de leche, to be precise). From the first identity training kits to the monumental work in FabrikamShipping SaaS, going through the identity labs in the windows azure platform training kit, keynote demos and occasional projects, the partnership with <strong>Tim, Matias, Lito, Johnny, PC, Iaco (signor Iacomuzzi!), Ariel, Nahuel, Diego, Fernando, Mariano, Nicholas, the \u201cother Matias\u201d<\/strong> and many others (sorry guys for not remembering all the names!) has been invaluable. You are probably not going to miss my OCS-grade nitpicking and inflexible quasi-religious ideas about how claims based identity should be messaged, but I will miss your professionalism, flexibility, exceptional work ethic, will to burn the midnight oil (remember that night in which the fire alarm rang in B18 (or was B24?) and when we came out we were practically the only ones in the place?) and especially all the common ground we built over the years. Best of luck you guys! <img decoding=\"async\" style=\"border-bottom-style: none;border-left-style: none;border-top-style: none;border-right-style: none\" class=\"wlEmoticon wlEmoticon-smile\" alt=\"Smile\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2011\/07\/5618.wlEmoticon_2D00_smile_5F00_404C1E32.png\" \/><\/em><\/p>\n<div style=\"clear:both\"><\/div>\n","protected":false},"excerpt":{"rendered":"<p>As promised yesterday, here there\u2019s one of the deliverables I mentioned. About one month ago we published the first release of a set of PowerShell cmdlets for ACS: wrappers for the ACS management APIs, which allow you to easily script tasks such as wiping a namespace, adding an OpenID provider, automating often-used provisioning&#8230;<\/p>\n","protected":false},"author":1,"featured_media":1361,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"footnotes":""},"categories":[8,34,49,5],"tags":[],"class_list":["post-335","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-acs","category-personal","category-powershell","category-wif"],"_links":{"self":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/posts\/335","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/comments?post=335"}],"version-history":[{"count":1,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/posts\/335\/revisions"}],"predecessor-version":[{"id":1675,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/posts\/335\/revisions\/1675"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/media\/1361"}],"wp:attachment":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/media?parent=335"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/categories?post=335"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/tags?post=335"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}