Update: It looks like SMA is not executing the script when a new Tenant is created, but rather when a subscription is added to the user.
Trying to get it confirmed from Microsoft if that is a bug that’s been introduced in one of the latest updates. See comments for more details.
Problem: When a new employee for TrueSec (our company) is logging into Azure Pack he has to be added to the “Tenants – TrueSec Employees” plan manually.
Solution: One way is to add a “signup code” to the plan and tell new employees to manually join the plan with that specific code. It could work, but does not feel like the most optimal solution.
The desired way would be if all new employees could be added to that plan automatically. Is that possible?
– Of course it is, with the help of SMA! Let me show one way to do this.
Pre-Requisits: Connection Asset, SMA Runbook, Link Runbook to a task.
In my case, I’m using the MgmtSvcAdmin asset which looks like this. But you can also create other types of Connections with working credentials. Just notice that you have to enter the name of the Admin Site server in the Asset, as the script will use that info. And the useraccount specified obviously need access to use the Admin site (to modify the subscriptions).
Add a new Runbook with the script below. In my case, I’m using ADFS to connect to the Admin site, so the script has to generate a ADFS token first.
if you are not using ADFS, you will have to modify the script to use a normal Windows authentication. It’s the most common way to authenticate, so there shouldn’t be any problems finding example code for.
Though, please note that the script is currently matching the new users e-mail address to (in our case) @truesec.com or @truesec.se. If you don’t use ADFS, it’s possible for a user to type any name they want during registration and then possibly get added to a plan they should not have access too.
And finally, add a new Automation Task, you do that under Clouds -> Automation.
Object: SPF Tenant
Action: Create
Runbook: New-Tenant
The script:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
workflow New-Tenant { param([object]$resourceObject) # write-output ($resourceObject.Name -split "_" | select -first 1) # Get Connection Credentials. Change Name to your own Asset. $con = Get-AutomationConnection -Name 'CLAZAS01_RU_SMA' $secpasswd = ConvertTo-SecureString $con.Password -AsPlainText -Force $ruSMAcreds = New-Object System.Management.Automation.PSCredential ($con.username, $secpasswd) # Execute commands on AzurePack Admin site. Connect with Asset Credentials InlineScript { $con=$USING:Con $ruSMAcreds=$USING:ruSMAcreds $resourceObject=$USING:resourceObject Invoke-Command -ComputerName $con.computername -Credential $ruSMAcreds -ArgumentList ($resourceObject.Name -split "_" | select -first 1),$con -ScriptBlock { param( $NewUserEmail, $con ) # We use ADFS for our Azure Pack site, so have to generate a ADFS Token first. function Get-AdfsToken([string]$adfsAddress, [PSCredential]$credential) { $clientRealm = 'http://azureservices/AdminSite' $allowSelfSignCertificates = $true Add-Type -AssemblyName 'System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' Add-Type -AssemblyName 'System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' $identityProviderEndpoint = New-Object -TypeName System.ServiceModel.EndpointAddress -ArgumentList ($adfsAddress + '/adfs/services/trust/13/usernamemixed') $identityProviderBinding = New-Object -TypeName System.ServiceModel.WS2007HttpBinding -ArgumentList ([System.ServiceModel.SecurityMode]::TransportWithMessageCredential) $identityProviderBinding.Security.Message.EstablishSecurityContext = $false $identityProviderBinding.Security.Message.ClientCredentialType = 'UserName' $identityProviderBinding.Security.Transport.ClientCredentialType = 'None' $trustChannelFactory = New-Object -TypeName System.ServiceModel.Security.WSTrustChannelFactory -ArgumentList $identityProviderBinding, $identityProviderEndpoint $trustChannelFactory.TrustVersion = [System.ServiceModel.Security.TrustVersion]::WSTrust13 if ($allowSelfSignCertificates) { $certificateAuthentication = New-Object -TypeName System.ServiceModel.Security.X509ServiceCertificateAuthentication $certificateAuthentication.CertificateValidationMode = 'None' $trustChannelFactory.Credentials.ServiceCertificate.SslCertificateAuthentication = $certificateAuthentication } $ptr = [System.Runtime.InteropServices.Marshal]::SecureStringToCoTaskMemUnicode($credential.Password) $password = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($ptr) [System.Runtime.InteropServices.Marshal]::ZeroFreeCoTaskMemUnicode($ptr) $trustChannelFactory.Credentials.SupportInteractive = $false $trustChannelFactory.Credentials.UserName.UserName = $credential.UserName $trustChannelFactory.Credentials.UserName.Password = $password #$credential.Password $rst = New-Object -TypeName System.IdentityModel.Protocols.WSTrust.RequestSecurityToken -ArgumentList ([System.IdentityModel.Protocols.WSTrust.RequestTypes]::Issue) $rst.AppliesTo = New-Object -TypeName System.IdentityModel.Protocols.WSTrust.EndpointReference -ArgumentList $clientRealm $rst.TokenType = 'urn:ietf:params:oauth:token-type:jwt' $rst.KeyType = [System.IdentityModel.Protocols.WSTrust.KeyTypes]::Bearer $rstr = New-Object -TypeName System.IdentityModel.Protocols.WSTrust.RequestSecurityTokenResponse $channel = $trustChannelFactory.CreateChannel() $token = $channel.Issue($rst, [ref] $rstr) $tokenString = ([System.IdentityModel.Tokens.GenericXmlSecurityToken]$token).TokenXml.InnerText; $result = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($tokenString)) return $result } # Fill in values for your environment. # ADFS Server address $adfsAddress = 'https://adfs.labcenteronline.com' $credentials=$ruSMAcred # Name and port for the Admin Site. $adminUri = 'https://adminsite.labcenteronline.com:30004' $secpasswd = ConvertTo-SecureString $con.Password -AsPlainText -Force $ruSMAcreds = New-Object System.Management.Automation.PSCredential ($con.username, $secpasswd) $token = Get-AdfsToken -adfsAddress https://adfs.labcenteronline.com -credential $ruSMAcreds $newuser = Get-MgmtSvcUser -Token $token -AdminUri $adminUri -DisableCertificateValidation -Name $NewUserEmail $uname=$newuser.name # Change the e-mail suffix to match your environment. if (($uname -like "*@truesec.com") -or ($uname -like "*@truesec.se")) { #TrueSec Employees # Replace DisplayName to match your Plan. $plan = Get-MgmtSvcPlan -Token $token -AdminUri $adminUri -DisableCertificateValidation -DisplayName "*Tenan*Truesec*" | where State -notlike "Decommissioned" | select -first 1 $planname=$plan.DisplayName # Get Current Subscriptions for user that matches the Plan to get added to. $currentsubs = Get-MgmtSvcSubscription -Token $token -AdminUri $adminUri -DisableCertificateValidation | where AccountAdminLiveEmailId -like "$uname" | where OfferFriendlyName -like "$planname" if ($currentsubs.count -lt $plan.MaxSubscriptionsPerAccount){ $newsubscription = Add-MgmtSvcSubscription -Token $token -AdminUri $adminUri -DisableCertificateValidation -AccountAdminLiveEmailId $uname -AccountAdminLivePuid $uname -PlanId $plan.id -FriendlyName $plan.DisplayName write-output "$uname has been added to $planname with subscriptionid $newsubscription" } else { Write-Output "User already has a subscriptions for $planname" } } else { write-output "Not a Truesec Employee, did not add user to any plan." } } } } |
I hope this helps you automating things in your environment. If you can think of any other great usages for SMA or have need for automating something. Please make a comment, maybe I’ll be able to assist.