{"id":319,"date":"2011-05-17T23:06:00","date_gmt":"2011-05-18T08:06:00","guid":{"rendered":"http:\/\/www.cloudidentity.com\/blog\/2011\/05\/17\/announcing-sample-acs-cmdlets-for-the-windows-azure-appfabric-access-control-service\/"},"modified":"2011-05-17T23:06:00","modified_gmt":"2011-05-18T08:06:00","slug":"announcing-sample-acs-cmdlets-for-the-windows-azure-appfabric-access-control-service","status":"publish","type":"post","link":"https:\/\/www.cloudidentity.com\/blog\/2011\/05\/17\/announcing-sample-acs-cmdlets-for-the-windows-azure-appfabric-access-control-service\/","title":{"rendered":"Announcing: Sample ACS Cmdlets for the Windows Azure AppFabric Access Control Service"},"content":{"rendered":"<p><a href=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2011\/05\/3051.powershell_5F00_554C330C.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=\"powershell\" border=\"0\" alt=\"powershell\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2011\/05\/3051.powershell_5F00_554C330C.png\" width=\"300\" height=\"150\" \/><\/a><\/p>\n<p>Long story short: <strong>we are releasing <a href=\"http:\/\/bit.ly\/ACScmdlets\">on Codeplex<\/a> <a href=\"http:\/\/bit.ly\/llnWl7\">a set of PowerShell cmdlets which wrap the management API of the Windows Azure AppFabric Access Control Service.<\/a> <\/strong><\/p>\n<p>This is hopefully for the joy of our IT admin friends who want to add ACS to their arsenal, but I bet that this will make many developers happy as well. I\u2019ve never really used PowerShell before, and I\u2019m using those cmdlets like crazy since the very first internal drop!<\/p>\n<p>You can use those new cmdlets to <strong>save repetitive provisioning processes in form of PowerShell scripts<\/strong>, and consistently reuse them just by passing as parameters the targeted namespace and corresponding management key. You can use them for <strong>backing up your namespace settings on file and restore them at a later time<\/strong>, or <strong>copy settings from one namespace to the other<\/strong>. You can easily <strong>integrate ACS management in your existing scripts<\/strong>, or even <strong>just use the cmdlets to perform quick queries and adjustments <\/strong>to your namespace directly <strong>from PowerShell ISE or the command line<\/strong>. In fact, you can do whatever you are used to do with PowerShell cmdlets <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\/05\/0003.wlEmoticon_2D00_smile_5F00_2E6DF6FF.png\" \/>. <\/p>\n<p><a href=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2011\/05\/5706.image_5F00_4E1CD0C7.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\/05\/5706.image_5F00_4E1CD0C7.png\" width=\"500\" height=\"386\" \/><\/a><\/p>\n<p>The initial set we are releasing today is not 100% exhaustive, for example we don\u2019t touch the service identities yet, but it already enables most of the scenarios we encountered. The command names are self-explanatory:<\/p>\n<table border=\"1\" cellspacing=\"0\" cellpadding=\"2\" width=\"400\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"200\">\n<p><strong>IPs<\/strong><\/p>\n<p><font face=\"Courier New\">Add-IdentityProvider              <br \/>Get-IdentityProvider               <br \/>Get-IdentityProviders               <br \/>Remove-IdentityProvider<\/font>             <\/p>\n<\/td>\n<td valign=\"top\" width=\"200\">\n<p><strong>RPs<\/strong><\/p>\n<p><font face=\"Courier New\">Add-RelyingParty              <br \/>Get-RelyingParties               <br \/>Get-RelyingParty               <br \/>Remove-RelyingParty<\/font><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"200\">\n<p><strong>Rules<\/strong><\/p>\n<p><font face=\"Courier New\">Add-DefaultPassThroughRules              <br \/>Add-Rule               <br \/>Get-Rule               <br \/>Get-Rules               <br \/>Remove-Rule<\/font>             <\/p>\n<\/td>\n<td valign=\"top\" width=\"200\">\n<p><strong>Rule Groups<\/strong><\/p>\n<p><font face=\"Courier New\">Add-RuleGroup              <br \/>Get-RuleGroup               <br \/>Get-RuleGroups               <br \/>Remove-RuleGroup<\/font><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"200\">\n<p><strong>Crypto<\/strong><\/p>\n<p><font face=\"Courier New\">Add-TokenEncryptionKey              <br \/>Add-TokenSigningKey               <br \/>Get-ServiceKey               <br \/>Get-ServiceKeys               <br \/>Remove-ServiceKey<\/font>             <\/p>\n<\/td>\n<td valign=\"top\" width=\"200\">\n<p><strong>Utils<\/strong><\/p>\n<p><font face=\"Courier New\">Get-AcsManagementToken<\/font><\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>There\u2019s just 23 of them, and we might shrink them further in the future. For example: do we really need an Add-DefaultPassThroughRules cmdlet or can we just rely on Add-Rule? You tell us!    <br \/>All cmdlets support get-help including the \u2013Full option, although things are not too verbose at the moment: in subsequent releases we\u2019ll tidy things up, but we wanted to put this in your hands ASAP.<\/p>\n<p>Now for the usual <strong>disclaimer<\/strong>:&#160; Those cmdlets are distributed in source code form and are not part of the product. you should consider them a code sample, even if we provide you with a setup that will automatically compile and install them so that you can use them without ever opening the project in visual studio if you don\u2019t want to. Of course we are happy to take your feedback, especially now that the package is still a bit rough on the edges, but you should always remember that those cmdlets are unsupported.     <br \/>Other disclaimer: this release have been thoroughly tested only on Windows 7 x64 SP1, and quickly tested on Windows 7 x86 SP1 and Windows 2008 R2 x64 SP1. There are known problems on older platforms, which we\u2019ll iron out moving forward. Think of this release as one preview.<\/p>\n<p>That said, I am sure you\u2019ll have a lot of fun using the cmdlets for exploring the features that ACS offers.<\/p>\n<h2>Some More Background, and One Example<\/h2>\n<p>If you want to manage your ACS namespaces, there\u2019s no shortage of options: you can take advantage of the management portal (new in 2.0) or you can use the OData API exposed via management service.<\/p>\n<p>In my team we make pretty heavy use of ACS, both for our internal tooling (for example managing content and events) and for the samples, demos and hands on lab we produce.    <br \/>In order to enable the scenario we want to implement, at setup time all of those deliverables require us to go through fixed sets of configuration steps in ACS. For example, when you use the template in the <a href=\"http:\/\/watoolkitwp7.codeplex.com\/\">Windows Azure Toolkit for Windows Phone 7<\/a> to generate an ACS-ready project, the initialization code needs to:<\/p>\n<ul>\n<li>Add Google as an IP <\/li>\n<li>Add Yahoo! as an IP <\/li>\n<li>Remove any RP which may collide with the new one <\/li>\n<li>Create the new RP <\/li>\n<li>Get rid of all the rules which may already be in the rule group we are targeting <\/li>\n<li>Generate all the pass-through rules for the various IPs <\/li>\n<\/ul>\n<p>This is a relatively simple sequence of operations; other setups we have to do, like the enterprise subscription provisioning flow we follow when we handle a new FabrikamShipping subscriber, are WAY more complicated.    <br \/>In order to automate those processes, we progressively populated a class library of C# wrappers for the ACS management APIs. Then we started including that library in the Setup folder of various projects, together with a console app which calls those wrappers in the sequence that the specific sample being set up dictates; for example, the sequence described above for the Windo<a href=\"http:\/\/watoolkitwp7.codeplex.com\/\">ws Azure toolkit for Windows Phone 7<\/a>.&#160; <br \/>In that specific case, the setup solution (it\u2019s <em>C:WAZToolkitForWP7SetupacsAcsSetup.sln<\/em> if you have the toolkit and you are curious) is almost<strong> 580 lines of code<\/strong>.<\/p>\n<p>Now, multiply that for all the projects we have (for the newest ones see <a href=\"http:\/\/blogs.msdn.com\/b\/vbertocci\/archive\/2011\/04\/11\/the-new-acs-ships.aspx\">this post<\/a>) and the number starts to look significant. Add it to the frequent requests we get from customers to extend the cmdlets we created for Windows Azure to other services in the Windows Azure platform, and you\u2019ll see why we decided to create a set of cmdlets for ACS.     <br \/>Quite frankly, it was also because it was a low hanging fruit for us. We already had our wrapper library for the ACS management API, and we had the cmdlets wrapper solution we used for generating the Windows Azure cmdlets; putting the two together was pretty straightforward.<\/p>\n<p>Once we had the right set of cmdlets we went ahead and re-created the sequence above in for of PowerShell script, and the improvement in respect to the AcsSetup.sln approach is impressive. Check it out:<\/p>\n<p><font face=\"Courier New\"><strong># Coordinates of your namespace<\/strong>       <br \/>$acsNamespace = &quot;&lt;yourNamespace&gt;&quot;;       <br \/>$mgmtKey = &quot;&lt;yourManagementKey&gt;&quot;;<\/font><\/p>\n<p><font face=\"Courier New\"><strong># Constants<\/strong>       <br \/><\/font><font face=\"Courier New\">$rpName = &quot;WazMobileToolkit&quot;;      <br \/>$groupName = &quot;Default Rule Group for $rpName&quot;;       <br \/>$signingSymmetricKey = &quot;2RGYmQiFT9uslnxTTUn9MFr\/nU+HeVwkmMJ6MwBNGuQ=&quot;;<\/font><\/p>\n<p><font face=\"Courier New\">$allowedIdentityProviders = @(&quot;Windows Live ID&quot;,&quot;Yahoo!&quot;, &quot;Google\u201d);<\/font><\/p>\n<p><font face=\"Courier New\"><strong># Include ACS Management SnapIn <\/strong>      <br \/>Add-PSSnapin ACSManagementToolsSnapIn;<\/font><\/p>\n<p><font face=\"Courier New\"><strong># Get the ACS management token for securing all subsequent API calls<\/strong>       <br \/>$mgmtToken = Get-AcsManagementToken -namespace $acsNamespace -managementKey $mgmtKey;<\/font><\/p>\n<p><font face=\"Courier New\"><strong># Configure Preconfigured Identity Providers <\/strong>      <br \/>Write-Output &quot;Add PreConfigured Identity Providers (Google and Yahoo!)&#8230;&quot;;       <br \/>$googleIp = Add-IdentityProvider -mgmtToken $mgmtToken -type &quot;Preconfigured&quot; \u2013preconfiguredIPType &quot;Google&quot;;       <br \/>$yahooIp = Add-IdentityProvider -mgmtToken $mgmtToken -type &quot;Preconfigured&quot; \u2013preconfiguredIPType &quot;Yahoo!&quot;;<\/font><\/p>\n<p><font face=\"Courier New\"><strong># Remove RP (if it already exists) <\/strong>      <br \/>Write-Output &quot;Remove Relying Party ($rpName) if exists&#8230;&quot;;       <br \/>Remove-RelyingParty -mgmtToken $mgmtToken -name $rpName;<\/font><\/p>\n<p><font face=\"Courier New\"><strong># Remove All Rules In Group (if they already exist) <\/strong>      <br \/>Write-Output &quot;Remove All Rules In Group ($groupName) if exists&#8230;&quot;;       <br \/>Get-Rules -mgmtToken $mgmtToken -groupName $groupName | ForEach-Object { Remove-Rule -mgmtToken $mgmtToken -rule $_ };<\/font><\/p>\n<p><font face=\"Courier New\"><strong># Create Relying Party <\/strong>      <br \/>Write-Output &quot;Create Relying Party ($rpName)&#8230;&quot;;       <br \/>$rp = Add-RelyingParty -mgmtToken $mgmtToken -name $rpName -realm &quot;uri:wazmobiletoolkittest&quot; -tokenFormat &quot;SWT&quot; -allowedIdentityProviders $allowedIdentityProviders -ruleGroup $groupName -signingSymmetricKey $signingSymmetricKey;<\/font><\/p>\n<p><font face=\"Courier New\"><strong># Generate default pass-through rules <\/strong>      <br \/>Write-Output &quot;Create Default Passthrough Rules for the configured IPs ($allowedIdentityProviders)&#8230;&quot;;       <br \/>$rp.IdentityProviders | ForEach-Object { Add-DefaultPassthroughRules -mgmtToken $mgmtToken -groupName $groupName -identityProviderName $_.Name }<\/font><\/p>\n<p><font face=\"Courier New\">Write-Output &quot;Done&quot;;<\/font><\/p>\n<p>Excluding the comments (but counting the Write-Output) those are 20 lines of very understandable code, which you can modify in notepad (typically just for the namespace and namespace key) and run with a simple double-click; or, if you are fancy, you can open it up in PowerShell ISE and execute it line by line if you want to. Does it show that I am excited about this? <img decoding=\"async\" style=\"border-bottom-style: none;border-left-style: none;border-top-style: none;border-right-style: none\" class=\"wlEmoticon wlEmoticon-openmouthedsmile\" alt=\"Open-mouthed smile\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2011\/05\/1563.wlEmoticon_2D00_openmouthedsmile_5F00_1A44B4A9.png\" \/><\/p>\n<p>Let\u2019s play a bit more. Let\u2019s say that you now want to add Facebook as an identity provider. First you\u2019ll need to add some config values at the beginning of the script:<\/p>\n<p><font face=\"Courier New\">$fbAppIPName = &quot;Facebook IP&quot;;     <br \/>$fbAppId = &quot;XXXXXXXXXXXXX&quot;;      <br \/>$fbAppSecret = &quot;XXXXXXXXXXXXX&quot;;<\/font><\/p>\n<p>We can even be fancy and subordinate the Facebook setup to the existance of non-empty facebook app coordinates in the script:<\/p>\n<p><font face=\"Courier New\">$facebookEnabled = (($fbAppId -ne &quot;&quot;) -and ($fbAppSecret -ne &quot;&quot;));<\/font><\/p>\n<p>Then we just add those few lines right where we create the preconfigured IPs:<\/p>\n<p><font face=\"Courier New\"><strong># Configure Facebook App Identity Provider<\/strong>      <br \/>if ($facebookEnabled)      <br \/>{      <br \/>&#160;&#160;&#160; Write-Output &quot;Add Facebook App Identity Provider ($fbAppIPName)&#8230;&quot;;      <br \/>&#160;&#160;&#160; <br \/>&#160;&#160;&#160; # Remove FB App IP (if exists)      <br \/>&#160;&#160;&#160; Remove-IdentityProvider -mgmtToken $mgmtToken -name $fbAppIPName;      <br \/>&#160;&#160;&#160; <br \/>&#160;&#160;&#160; # Add FB App IP      <br \/>&#160;&#160;&#160; $fbIp = Add-IdentityProvider -mgmtToken $mgmtToken -type &quot;FacebookApp&quot; -name $fbAppIPName -fbAppId $fbAppId -fbAppSecret $fbAppSecret;      <br \/>}<\/font><\/p>\n<p>Super straightforward; and the part that I love is that you can just test those commands one by one and see the results immediately, saving them in the script only when you are certain they do what you want them to do. For management tasks, it definitely beats fiddling with the debugger and the immediate window.<\/p>\n<p>Want to play a bit more? Sure. One thing I often need to do is wiping a namespace clean after I did a demo during a session. Sometimes I have many sessions in a day, from time to time even back to back: as you can imagine, clicking around the portal for deleting entities is not fun nor very fast. But now I can just double click on the following script and I am done!<\/p>\n<p><font face=\"Courier New\">$acsNamespace = &quot;holacsfederation&quot;;     <br \/>$mgmtKey = &quot;XXXXXXXXXXXXXXXXXXXX&quot;;      <br \/><strong># Include ACS Management SnapIn<\/strong>      <br \/>Add-PSSnapin ACSManagementToolsSnapIn;<\/font><\/p>\n<p><font face=\"Courier New\">$mgmtToken = Get-AcsManagementToken -namespace $acsNamespace -managementKey $mgmtKey;     <br \/>Write-Output &quot;Wiping IPs (and associated rules)&quot;;      <br \/>Get-IdentityProviders -mgmtToken $mgmtToken | where {$_.SystemReserved -eq $false} | ForEach-Object { Remove-IdentityProvider -mgmtToken $mgmtToken -name $_.Name };      <br \/>Write-Output &quot;Wiping RPs (and associated rules)&quot;;      <br \/>Get-RelyingParties -mgmtToken $mgmtToken | where {$_.SystemReserved -eq $false} | ForEach-Object { Remove-RelyingParty -mgmtToken $mgmtToken -name $_.Name };      <br \/>Write-Output &quot;Wiping Rule Groups&quot;;      <br \/>Get-RuleGroups -mgmtToken $mgmtToken | where {$_.SystemReserved -eq $false} | ForEach-Object { Remove-RuleGroup -mgmtToken $mgmtToken -name $_.Name };<\/font><\/p>\n<p>Here I delete all IPs (which will delete the associated rules), all RPs and all rule groups. All three commands have the same structure. Let\u2019s pick the IP one:<\/p>\n<p><font face=\"Courier New\">Get-IdentityProviders -mgmtToken $mgmtToken      <br \/>&#160;&#160;&#160;&#160; | where {$_.SystemReserved -eq $false}       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; | ForEach-Object { Remove-IdentityProvider -mgmtToken $mgmtToken -name $_.Name };<\/font><\/p>\n<p>Get-IdentityProviders returns all IPs in the namespace; the where clause excludes the system reserved ones (Windows Live ID) which we\u2019d be unable to delete anyway, then the ForEach-Object cycles through all the IPs and removes them. You\u2019ve got to love PowerShell piping.<\/p>\n<p>Well, this barely scratches the surface of what you can do with the ACS cmdlets. <a href=\"http:\/\/bit.ly\/ACScmdlets\">Please do check them out!<\/a> We look forward for your feedback, and for once not just from developers! <img decoding=\"async\" style=\"border-bottom-style: none;border-left-style: none;border-top-style: none;border-right-style: none\" class=\"wlEmoticon wlEmoticon-winkingsmile\" alt=\"Winking smile\" src=\"http:\/\/cloudidentity.com\/blog\/wp-content\/uploads\/2011\/05\/0728.wlEmoticon_2D00_winkingsmile_5F00_403A64FF.png\" \/><\/p>\n<div style=\"clear:both\"><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Long story short: we are releasing on Codeplex a set of PowerShell cmdlets which wrap the management API of the Windows Azure AppFabric Access Control Service. This is hopefully for the joy of our IT admin friends who want to add ACS to their arsenal, but I bet that this will make many&#8230;<\/p>\n","protected":false},"author":1,"featured_media":1350,"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":[1],"tags":[],"class_list":["post-319","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/posts\/319","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=319"}],"version-history":[{"count":0,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/posts\/319\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/media\/1350"}],"wp:attachment":[{"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/media?parent=319"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/categories?post=319"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cloudidentity.com\/blog\/wp-json\/wp\/v2\/tags?post=319"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}