AdobeUM.AzureAD.psm1
function Import-PFXCert { <# .SYNOPSIS Import a certificate with a private key from file .PARAMETER CertPwd Password to open PFX .PARAMETER CertPath Path to PFX File .NOTES If you hard-code the password in a script utilizing this function, you should ensure the script is itself, somewhere secure .EXAMPLE Import-PFXCert -CertPwd "ASDF" -CertPath "C:\Cert.pfx" #> Param ( [string]$CertPwd, [ValidateScript({Test-Path -Path $_})] [Parameter(Mandatory=$true)] [string]$CertPath ) $Collection = [System.Security.Cryptography.X509Certificates.X509Certificate2Collection]::new() #Because I could not get the private key utilizing "cert:\etc\etc" $Collection.Import($CertPath, $CertPwd, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::PersistKeySet) return $Collection[0] } function ConvertTo-Base64URL { <# .SYNOPSIS Converts a byte[], to a Base64URL encoded string .PARAMETER Item A byte[] .EXAMPLE ConvertTo-Base64URL -Item "VGhpcyBpcyBhIHRlc3Q=" #> Param ( [Parameter(Mandatory=$true)] $Item ) return [Convert]::ToBase64String($Item).Split("=")[0].Replace('+', '-').Replace('/', '_') } function ConvertFrom-Base64URL { <# .SYNOPSIS Converts a Base64Url string, to a decoded ASCII string .PARAMETER Item A base64url string .EXAMPLE ConvertFrom-Base64URL -Item "VGhpcyBpcyBhIHRlc3Q" #> Param ( [Parameter(Mandatory=$true)] [string]$String ) return [System.Text.ASCIIEncoding]::ASCII.GetString([convert]::FromBase64String((ConvertFrom-Base64URLToBase64 -String $String))) } function ConvertFrom-Base64URLToBase64 { <# .SYNOPSIS Converts a Base64Url string, to a .Net base64 string .PARAMETER Item A base64url string .EXAMPLE ConvertFrom-Base64URLToBase64 -Item "VGhpcyBpcyBhIHRlc3Q" #> Param ( [Parameter(Mandatory=$true)] [string]$String ) $String = $String.Replace('-', '+').Replace('_', '/') while ((($String.Length)*6)%8-ne 0) { $String = $String+"=" } return $String } function ConvertTo-JavaTime { <# .SYNOPSIS Converts the [datetime] object passed into a java compliant numerical representation. (milliseconds since 1/1/1970) .PARAMETER DateTimeObject A DateTime to be converted .EXAMPLE ConvertTo-JavaTime -DateTimeObject ([DateTime]::Now) #> Param ( [Parameter(Mandatory=$true)] [DateTime]$DateTimeObject ) # Take DateTime, convert to file time (100 nano second ticks since 1/1/1607). Subtract 1/1/1970 from that using the same 100nanoticks. Then multiply to convert from nanoticks to milliseconds since 1/1/1970. return [int64](($DateTimeObject.ToFileTimeUtc()-[DateTime]::Parse("01/01/1970").ToFileTimeUtc())*0.0001) } function ConvertFrom-JavaTime { <# .SYNOPSIS Converts the java compliant numerical representation of time to a .net [datetime] object. .PARAMETER JavaTime A JavaTime to be converted .EXAMPLE ConvertFrom-JavaTime -JavaTime 1500000000000 #> Param ( [Parameter(Mandatory=$true)] [int64]$JavaTime ) # Take the javatime, multiply it by 10000 to convert from millisecond ticks to 100 nanosecond ticks. Then add the 100 nano second tickets since 1970 to that number. This gives us the current file time. # Then convert file time to [datetime] object return [DateTime]::FromFileTimeUtc($JavaTime*10000+[DateTime]::Parse("01/01/1970").ToFileTimeUtc()) } function New-ClientInformation { <# .SYNOPSIS Creates an object to contain client information such as service account details. .PARAMETER APIKey Your service account's APIkey/ClientID as returned by https://console.adobe.io/ .PARAMETER OrganizationID Your OrganizationID as returned by https://console.adobe.io/ .PARAMETER ClientSecret Your service account's ClientSecret as returned by https://console.adobe.io/ .PARAMETER TechnicalAccountID Your service account's TechnicalAccountID as returned by https://console.adobe.io/ .PARAMETER TechnicalAccountEmail Your service account's TechnicalAccountEmail as returned by https://console.adobe.io/ .OUTPUTS ClientInformation object to be passed to further commands .EXAMPLE New-ClientInformation -APIKey "1111111111111222222333" -OrganizationID "22222222222222@AdobeOrg" -ClientSecret "xxxx-xxxx-xxxx-xxxx" -TechnicalAccountID "abcdf@techacct.adobe.com" -TechnicalAccountEmail "xxxx-xxxx-xxxx-xxxx@techacct.adobe.com" #> Param ( [Parameter(Mandatory=$true)] [string]$APIKey, [Parameter(Mandatory=$true)] [string]$OrganizationID, [Parameter(Mandatory=$true)] [string]$ClientSecret, [Parameter(Mandatory=$true)] [string]$TechnicalAccountID, [Parameter(Mandatory=$true)] [string]$TechnicalAccountEmail ) return New-Object -TypeName PSObject -ArgumentList @{ APIKey = $APIKey; # ClientID ClientID = $APIKey; # Alias, adobe flip flops on what they call this OrgID = $OrganizationID; ClientSecret = $ClientSecret; TechnicalAccountID = $TechnicalAccountID; TechnicalAccountEmail = $TechnicalAccountEmail; Token=$null; } } function Get-AdobeAuthToken { <# .SYNOPSIS Adds an adobe auth token to the ClientInformation object passed to it .PARAMETER ClientInformation Your ClientInformation object .PARAMETER SignatureCert The cert that is attached to the specified account. Must have private key. Check which cert at https://console.adobe.io/ .PARAMETER AuthTokenURI URI of the Adobe Auth Service. Defaults to https://ims-na1.adobelogin.com/ims/exchange/jwt/ .PARAMETER ExpirationInHours When the request token should expire in hours. Defaults to 1 .OUTPUTS Attached auth token to ClientInformation.Token .NOTES Create JWT https://www.adobe.io/apis/cloudplatform/console/authentication/createjwt/jwt_nodeJS.html https://github.com/lambtron/nextbus/blob/master/node_modules/jwt-simple/lib/jwt.js https://jwt.io/ .EXAMPLE Get-AdobeAuthToken -ClientInformation $MyClient -SignatureCert $Cert -ExpirationInHours 12 #> Param ( [Parameter(Mandatory=$true)] $ClientInformation, [ValidateScript({$null -ne $_.PrivateKey})] [Parameter(Mandatory=$true)] $SignatureCert, [string]$AuthTokenURI="https://ims-na1.adobelogin.com/ims/exchange/jwt/", [int]$ExpirationInHours=1 ) $PayLoad = New-Object -TypeName PSObject -Property @{ iss=$ClientInformation.OrgID; sub=$ClientInformation.TechnicalAccountID; aud="https://ims-na1.adobelogin.com/c/"+$ClientInformation.APIKey; "https://ims-na1.adobelogin.com/s/ent_user_sdk"=$true;#MetaScope exp=(ConvertTo-JavaTime -DateTimeObject ([DateTime]::Now.AddHours($ExpirationInHours))); } # Header for the JWT $Header = ConvertTo-Json -InputObject (New-Object PSObject -Property @{typ="JWT";"alg"="RS256"}) -Compress # Body of the JWT. This is our actual request $JWT = ConvertTo-Base64URL -Item ([System.Text.ASCIIEncoding]::ASCII.GetBytes((ConvertTo-Json -InputObject $PayLoad -Compress))) # Join them together. as base64 strings, with a "." between them $JWT = (ConvertTo-Base64URL -Item ([System.Text.ASCIIEncoding]::ASCII.GetBytes($Header)))+"."+$JWT # Sign the data $JWTSig = ConvertTo-Base64URL -Item ($SignatureCert.PrivateKey.SignData([System.Text.ASCIIEncoding]::UTF8.GetBytes($JWT), [System.Security.Cryptography.HashAlgorithmName]::SHA256, [System.Security.Cryptography.RSASignaturePadding]::Pkcs1)) # Append the signature. This is now a complete JWT $JWT = $JWT+"."+$JWTSig # Now we request the auth token $Body = "client_id=$($ClientInformation.APIKey)&client_secret=$($ClientInformation.ClientSecret)&jwt_token=$JWT" $ClientInformation.Token = Invoke-RestMethod -Method Post -Uri $AuthTokenURI -Body $Body -ContentType "application/x-www-form-urlencoded" } function Get-AdobeUsers { <# .SYNOPSIS Gets all users from the adobe API .PARAMETER ClientInformation Your ClientInformation object .PARAMETER UM_Server The adobe user management uri. Defaults to "https://usermanagement.adobe.io/v2/usermanagement/" .NOTES https://www.adobe.io/apis/cloudplatform/usermanagement/docs/samples/samplequery.html .EXAMPLE Get-AdobeUsers -ClientInformation $MyClient #> Param ( [string]$UM_Server = "https://usermanagement.adobe.io/v2/usermanagement/", [ValidateScript({$null -ne $_.Token})] [Parameter(Mandatory=$true)] $ClientInformation ) #Store the results here $Results = @() # URI of the query endpoint $URIPrefix = "$UM_Server$($ClientInformation.OrgID)/users?page=" $Page =0 # Request headers $Headers = @{ Accept="application/json"; "Content-Type"="application/json"; "x-api-key"=$ClientInformation.APIKey; Authorization="Bearer $($ClientInformation.Token.access_token)" } # Query, looping through each page, until we have all users. while($true) { $QueryResponse = Invoke-RestMethod -Method Get -Uri ($URIPrefix+$Page.ToString()) -Header $Headers # Currently not required, but other queries will just keep dumping the same users as you loop though pages if ($null -ne $Results -and $QueryResponse[0].id -in $Results.id) { break; } $Results += $QueryResponse $Page++; # Different API endpoints have different ways of telling you if you are done. if ($QueryResponse.lastPage -eq $true -or $null -eq $QueryResponse -or $QueryResponse.Length -eq 0) { break; } } return $Results } function Get-AdobeGroups { <# .SYNOPSIS Grab a list of all groups, or if provided an ID, returns the group related to the ID .PARAMETER ClientInformation Your ClientInformation object .PARAMETER UM_Server The adobe user management uri. Defaults to "https://usermanagement.adobe.io/v2/usermanagement/" .PARAMETER GroupID If you wish to query for a single group instead, put the group ID here .NOTES https://www.adobe.io/apis/cloudplatform/usermanagement/docs/samples/samplequery.html .EXAMPLE Get-AdobeGroups -ClientInformation $MyClient .EXAMPLE Get-AdobeGroups -ClientInformation $MyClient -GroupID "222242" #> Param ( [string]$UM_Server = "https://usermanagement.adobe.io/v2/usermanagement/", $GroupID = $null, [ValidateScript({$null -ne $_.Token})] [Parameter(Mandatory=$true)] $ClientInformation ) #See https://www.adobe.io/apis/cloudplatform/usermanagement/docs/samples/samplequery.html $Results = @() if ($null -eq $GroupID) { $URIPrefix = "$UM_SERVER$($ClientInformation.OrgID)/user-groups?page=" } else { $URIPrefix = "$UM_SERVER$($ClientInformation.OrgID)/user-groups/$GroupID" } $Page =0 # Request headers $Headers = @{Accept="application/json"; "Content-Type"="application/json"; "x-api-key"=$ClientInformation.APIKey; Authorization="Bearer $($ClientInformation.Token.access_token)"} if ($null -eq $GroupID) { while($true) { $QueryResponse = Invoke-RestMethod -Method Get -Uri ($URIPrefix+$Page.ToString()) -Header $Headers if ($null -ne $Results -and $QueryResponse[0].groupId -in $Results.groupId) { break; #Why you ask? Because Adobe will just return any results they can anyway! If you have 1 page of results, and you ask for page 4, do they error? Noooo. Do they say last page? Nooo! } $Results += $QueryResponse $Page++; if ($QueryResponse.lastPage -eq $true -or $null -eq $QueryResponse -or $QueryResponse.Length -eq 0) { break } } } else { $Results = Invoke-RestMethod -Method Get -Uri $URIPrefix -Header $Headers } return $Results } function Get-AdobeGroupMembers { <# .SYNOPSIS Grab all members of the specified group .PARAMETER ClientInformation Your ClientInformation object .PARAMETER UM_Server The adobe user management uri. Defaults to "https://usermanagement.adobe.io/v2/usermanagement/" .PARAMETER GroupID The ID of the group to query .NOTES https://www.adobe.io/apis/cloudplatform/usermanagement/docs/samples/samplequery.html .EXAMPLE Get-AdobeGroupMembers -ClientInformation $MyClient -GroupID "222424" #> Param ( [string]$UM_Server = "https://usermanagement.adobe.io/v2/usermanagement/", [ValidateScript({$null -ne $_.Token})] [Parameter(Mandatory=$true)] $ClientInformation, [Parameter(Mandatory=$true)] [string]$GroupID ) #See https://www.adobe.io/apis/cloudplatform/usermanagement/docs/samples/samplequery.html $Results = @() $URIPrefix = "$UM_SERVER$($ClientInformation.OrgID)/user-groups/$GroupID/users?page=" $Page = 0 # Request headers $Headers = @{Accept="application/json"; "Content-Type"="application/json"; "x-api-key"=$ClientInformation.APIKey; Authorization="Bearer $($ClientInformation.Token.access_token)"} while($true) { $QueryResponse = Invoke-RestMethod -Method Get -Uri ($URIPrefix) -Header $Headers if ($null -ne $Results -and $QueryResponse[0].id -in $Results.id) { break; #Why you ask? Because Adobe will just return any results they can anyway! If you have 1 page of results, and you ask for page 4, do they error? Noooo. Do they say last page? Nooo! } $Results += $QueryResponse $Page++; if ($QueryResponse.lastPage -eq $true -or $null -eq $QueryResponse -or $QueryResponse.Length -eq 0) { break } } return $Results } function Get-AdobeGroupAdmins { <# .SYNOPSIS Grab all admins of the specified group .PARAMETER ClientInformation Your ClientInformation object .PARAMETER UM_Server The adobe user management uri. Defaults to "https://usermanagement.adobe.io/v2/usermanagement/" .PARAMETER GroupID The ID of the group to query .NOTES https://www.adobe.io/apis/cloudplatform/usermanagement/docs/samples/samplequery.html .EXAMPLE Get-AdobeGroupAdmins -ClientInformation $MyClient -GroupID "222424" #> Param ( $UM_Server="https://usermanagement.adobe.io/v2/usermanagement/", [ValidateScript({$null -ne $_.Token})] [Parameter(Mandatory=$true)] $ClientInformation, [Parameter(Mandatory=$true)] [string]$GroupID ) #See https://www.adobe.io/apis/cloudplatform/usermanagement/docs/samples/samplequery.html $Results = @() $URIPrefix = "$UM_SERVER$($ClientInformation.OrgID)/user-groups/$GroupID/admins?page=" $Page =0 # Request headers $Headers = @{Accept="application/json"; "Content-Type"="application/json"; "x-api-key"=$ClientInformation.APIKey; Authorization="Bearer $($ClientInformation.Token.access_token)"} while($true) { $QueryResponse = Invoke-RestMethod -Method Get -Uri ($URIPrefix) -Header $Headers if ($null -ne $Results -and $QueryResponse[0].id -in $Results.id) { break; #Why you ask? Because Adobe will just return any results they can anyway! If you have 1 page of results, and you ask for page 4, do they error? Noooo. Do they say last page? Nooo! } $Results += $QueryResponse $Page++; if ($QueryResponse.lastPage -eq $true -or $null -eq $QueryResponse -or $QueryResponse.Length -eq 0) { break } } return $Results } function New-CreateUserRequest { <# .SYNOPSIS Creates a "CreateUserRequest" object. This object can then be converted to JSON and sent to create a new user .PARAMETER FirstName User's First name .PARAMETER LastName User's Last Name .PARAMETER Email User's Email and ID .PARAMETER Country Defaults to AU. This cannot be changed later. (Per adobe documentation) .PARAMETER AdditionalActions An array of additional actions to add to the request. (Like add to group) .NOTES See https://www.adobe.io/apis/cloudplatform/usermanagement/docs/samples/samplemultiaction.html This should be posted to https://usermanagement.adobe.io/v2/usermanagement/action/{myOrgID} .EXAMPLE New-CreateUserRequest -FirstName "John" -LastName "Doe" -Email "John.Doe@domain.com" #> Param ( [Parameter(Mandatory=$true)] [string]$FirstName, [Parameter(Mandatory=$true)] [string]$LastName, [Parameter(Mandatory=$true)] [string]$Email, [string]$Country="AU", $AdditionalActions=@() ) # Parameters to create a new federatedID $FederatedIDParameters = New-Object -TypeName PSObject -Property @{email=$Email;country=$Country;firstname=$FirstName;lastname=$LastName} # Federated ID creation action $FederatedIDAction = New-Object -TypeName PSObject -Property @{createFederatedID=$FederatedIDParameters} # Add any additional actions $AdditionalActions = @()+ $FederatedIDAction + $AdditionalActions # Return the new request return (New-Object -TypeName PSObject -Property @{user=$Email;do=@()+$AdditionalActions}) } function New-RemoveUserRequest { <# .SYNOPSIS Creates a "RemoveUserRequest" object. This object can then be converted to JSON and sent to remove a user frin adibe .PARAMETER UserName User's ID, usually e-mail .PARAMETER AdditionalActions An array of additional actions to add to the request. (Like add to group) .NOTES See https://www.adobe.io/apis/cloudplatform/usermanagement/docs/samples/samplemultiaction.html This should be posted to https://usermanagement.adobe.io/v2/usermanagement/action/{myOrgID} .EXAMPLE New-RemoveUserRequest -UserName "john.doe@domain.com" #> Param ( [Parameter(Mandatory=$true)] [string]$UserName, $AdditionalActions=@() ) $RemoveAction = New-Object -TypeName PSObject -Property @{removeFromOrg=(New-Object -TypeName PSObject)} $AdditionalActions = @() + $RemoveAction + $AdditionalActions return (New-Object -TypeName PSObject -Property @{user=$UserName;do=@()+$AdditionalActions}) } function New-UpdateUserRequest { <# .SYNOPSIS Creates a "UpdateUserRequest" object. This object can then be converted to JSON and sent to update an existing user .PARAMETER UserName User's ID, usually e-mail .PARAMETER AdditionalActions An array of additional actions to add to the request. (Like add to group) .NOTES See https://www.adobe.io/apis/cloudplatform/usermanagement/docs/samples/samplemultiaction.html This should be posted to https://usermanagement.adobe.io/v2/usermanagement/action/{myOrgID} .EXAMPLE New-UpdateUserRequest -FirstName "John" -LastName "Doe" -Email "John.Doe@domain.com" #> Param ( [Parameter(Mandatory=$true)] [string]$UserName, $AdditionalActions=@() ) $UpdateAction = New-Object -TypeName PSObject -Property @{update=(New-Object -TypeName PSObject)} # Add any additional actions $AdditionalActions = @()+ $UpdateAction + $AdditionalActions # Return the new request" return (New-Object -TypeName PSObject -Property @{user=$UserName;do=@()+$AdditionalActions}) } function New-RemoveUserFromGroupRequest { <# .SYNOPSIS Creates a request to remove a user from an Adobe group. This will need to be posted after being converted to a JSON .PARAMETER UserName User's ID, usually e-mail .PARAMETER GroupName Name of the group to remove the user from .NOTES See https://www.adobe.io/apis/cloudplatform/usermanagement/docs/samples/samplemultiaction.html This should be posted to https://usermanagement.adobe.io/v2/usermanagement/action/{myOrgID} .EXAMPLE New-RemoveUserFromGroupRequest -UserName "john.doe@domain.com" -GroupName "My User Group" #> Param ( [Parameter(Mandatory=$true)] [string]$UserName, [Parameter(Mandatory=$true)] $GroupName ) $RemoveMemberAction = New-GroupUserRemoveAction -Groups $GroupName return (New-Object -TypeName PSObject -Property @{user=$UserName;do=@()+$RemoveMemberAction}) } function New-GroupUserAddAction { <# .SYNOPSIS Creates a "Add to group" action. Actions fall under requests. This will have to be added to a request, then json'd and submitted to adobe's API .PARAMETER Groups An array of groups that something should be added to .NOTES See https://www.adobe.io/apis/cloudplatform/usermanagement/docs/samples/samplemultiaction.html This should be posted to https://usermanagement.adobe.io/v2/usermanagement/action/{myOrgID} .EXAMPLE New-GroupUserAddAction -Groups "My User Group" #> Param ( [Parameter(Mandatory=$true)] $Groups ) $Params = New-Object -TypeName PSObject -Property @{group=@()+$Groups} return (New-Object -TypeName PSObject -Property @{add=$Params}) } function New-GroupUserRemoveAction { <# .SYNOPSIS Creates a "Remove from group" action. Actions fall under requests. This will have to be added to a request, then json'd and submitted to adobe's API .PARAMETER Groups An array of groups that something should be removed from .NOTES See https://www.adobe.io/apis/cloudplatform/usermanagement/docs/samples/samplemultiaction.html This should be posted to https://usermanagement.adobe.io/v2/usermanagement/action/{myOrgID} .EXAMPLE New-GroupUserRemoveAction -Groups "My User Group" #> Param ( [Parameter(Mandatory=$true)] $Groups ) $Params = New-Object -TypeName PSObject -Property @{usergroup=@()+$Groups} return (New-Object -TypeName PSObject -Property @{remove=$Params}) } function New-AddToGroupRequest { <# .SYNOPSIS Creates a "Add user to group" request. This will need to be json'd and sent to adobe .PARAMETER Groups An array of groups that something should be added to .PARAMETER User A User to be added to the Group(s) .NOTES See https://www.adobe.io/apis/cloudplatform/usermanagement/docs/samples/samplemultiaction.html This should be posted to https://usermanagement.adobe.io/v2/usermanagement/action/{myOrgID} .EXAMPLE New-AddToGroupRequest -Groups "My User Group" -User "John.Doe@domain.com" #> Param ( [Parameter(Mandatory=$true)] [string]$User, [Parameter(Mandatory=$true)] $Groups ) $GroupAddAction = New-GroupUserAddAction -GroupNames $Groups return (New-Object -TypeName PSObject -Property @{user=$User;do=@()+$GroupAddAction}) } function New-RemoveFromGroupRequest { <# .SYNOPSIS Creates a "Remove user from group" request. This will need to be json'd and sent to adobe .PARAMETER Groups An array of groups that something should be removed from .PARAMETER User A User to be removed from the Group(s) .NOTES See https://www.adobe.io/apis/cloudplatform/usermanagement/docs/samples/samplemultiaction.html This should be posted to https://usermanagement.adobe.io/v2/usermanagement/action/{myOrgID} .EXAMPLE New-RemoveFromGroupRequest -Groups "My User Group" -User "John.Doe@domain.com" #> Param ( [Parameter(Mandatory=$true)] [string]$User, [Parameter(Mandatory=$true)] $Groups ) $GroupRemoveAction = Create-GroupRemoveAction -GroupNames $Groups return (New-Object -TypeName PSObject -Property @{user=$User;do=@()+$GroupRemoveAction}) } function Expand-JWTInformation { <# .SYNOPSIS Unpacks a JWT object into it's header, and body components. (Human readable format) .PARAMETER JWTObject JWT To unpack. In format of {Base64Header}.{Base64Body}.{Base64Signature} .PARAMETER SigningCert A certificate with the necesary public key to verify signature block. Can be null, will not validate signature. .NOTES See https://www.adobe.io/apis/cloudplatform/usermanagement/docs/samples/samplemultiaction.html This should be posted to https://usermanagement.adobe.io/v2/usermanagement/action/{myOrgID} .EXAMPLE Expand-JWTInformation -JWTObject "xxxx.xxxx.xxx" #> Param ( [ValidateScript({$_.Split(".").Length -eq 3})] [Parameter(Mandatory=$true)] [string]$JWTObject, $SigningCert ) $JWTParts = $JWTObject.Split(".") $Header =(ConvertFrom-Json -InputObject (ConvertFrom-Base64URL -String $JWTParts[0])); $RawData = [System.Text.ASCIIEncoding]::ASCII.GetBytes($JWTParts[0]+"."+$JWTParts[1]) $Signature = [System.Convert]::FromBase64String((ConvertFrom-Base64URLToBase64 -String $JWTParts[2])) $Valid = $null if ($SigningCert -and $Header.alg.StartsWith("RS")) { $HAN = $null if ($Header.alg.EndsWith("256")) { $HAN = [System.Security.Cryptography.HashAlgorithmName]::SHA256 } elseif ($Header.alg.EndsWith("512")) { $Han = [System.Security.Cryptography.HashAlgorithmName]::SHA512 } elseif ($Header.alg.EndsWith("384")) { $Han = [System.Security.Cryptography.HashAlgorithmName]::SHA384 } if ($HAN) { $Valid = $SigningCert.PublicKey.Key.VerifyData($RawData, $Signature, $Han, [System.Security.Cryptography.RSASignaturePadding]::Pkcs1) } } return (New-Object -TypeName PSObject -ArgumentList @{ Header=$Header; Body=(ConvertFrom-Json -InputObject (ConvertFrom-Base64URL -String $JWTParts[1])); SignatureValid=$Valid }) } function Send-UserManagementRequest { <# .SYNOPSIS Sends a request, or array of requests, to adobe's user management endpoint .PARAMETER ClientInformation ClientInformation object containing service account info and token .PARAMETER Requests An array of requests to send to adobe .NOTES See the Create-*Request .EXAMPLE Send-UserManagementRequest -ClientInformation $MyClientInfo -Requests (New-CreateUserRequest -FirstName "John" -LastName "Doe" -Email "john.doe@domain.com" -Country="AU") #> Param ( [ValidateScript({$null -ne $_.Token})] [Parameter(Mandatory=$true)]$ClientInformation, $Requests ) # Ensure is array $Request = @()+$Requests $Request = ConvertTo-Json -InputObject $Request -Depth 10 -Compress $URI = "https://usermanagement.adobe.io/v2/usermanagement/action/$($ClientInformation.OrgID)" $Headers = @{Accept="application/json"; "Content-Type"="application/json"; "x-api-key"=$ClientInformation.APIKey; Authorization="Bearer $($ClientInformation.Token.access_token)"} return (Invoke-RestMethod -Method Post -Uri $URI -Body $Request -Header $Headers) } function New-SyncADGroupRequest { <# .SYNOPSIS Creates an array of requests that, when considered together, ensures an Adobe group will mirror an AD group .PARAMETER ADGroupID Active Directory Group Identifier. The source group to mirror to adobe .PARAMETER AdobeGroupID Adobe group ID as retured from Get-AdobeGroups .PARAMETER ClientInformation Service account information including token .EXAMPLE New-SyncADGroupRequest -ADGroupID "SG-My-Approved-Adobe-Users" -AdobeGroupID "111222422" -ClientInformation $MyClientInfo #> Param ( [Parameter(Mandatory=$true)] [string]$ADGroupID, [Parameter(Mandatory=$true)] [string]$AdobeGroupID, [ValidateScript({$null -ne $_.Token})] [Parameter(Mandatory=$true)] $ClientInformation ) # Grab a list of all adobe groups $AdobeGroupInfo = Get-AdobeGroups -GroupID $AdobeGroupID -ClientInformation $ClientInformation # Grab a list of users in the Active Directory group $ADGroupMembers = Get-AzureADGroup -SearchString $ADGroupID | Get-AzureADGroupMember # Get extended property data on all users. (So we can get e-mail) $ADUsers = @() foreach ($ADGroupMember in $ADGroupMembers) { $ADUsers += Get-AzureADUser -ObjectID $ADGroupMember.ObjectId } # Grab a list of users from the adobe group $Members = (Get-AdobeGroupMembers -ClientInformation $ClientInformation -GroupID $AdobeGroupID).username $FederatedIDs = Get-AdobeUsers -ClientInformation $ClientInformation | Where-Object userType -eq federatedID #Results $Request = @() # Find missing users, and create requests to add them to adobe foreach ($ADUser in $ADUsers) { #If adobe group does not contain ad user if ($Members.Length -le 0 -or $ADUser.mail -notin $Members) { $AddToGroup = New-GroupUserAddAction -Groups $AdobeGroupInfo.name #Need to add if ($ADUser.mail -in $FederatedIDs.email) { $Request += New-UpdateUserRequest -UserName $ADUser.mail -AdditionalActions $AddToGroup } else { $Request += New-CreateUserRequest -FirstName $ADUser.GivenName -LastName $ADUser.SurName -Email $ADUser.mail -Country "AU" -AdditionalActions $AddToGroup } } } # Find excess members and create requests to remove them if ($ADUsers) { foreach ($Member in $Members) { if ($Member -notin $ADUsers.mail) { #Need to remove $Request += New-RemoveUserFromGroupRequest -UserName $Member -GroupName $AdobeGroupInfo.name } } } # return our list of requests return $Request } function New-RemoveUnusedAbobeUsersRequest { <# .SYNOPSIS Creates an array of requests that, when considered together, removes all users that are not admins, and not part of any user groups .PARAMETER ClientInformation Service account information including token .EXAMPLE New-RemoveUnusedAbobeUsersRequest -ClientInformation $MyClientInfo #> Param ( [ValidateScript({$null -ne $_.Token})] [Parameter(Mandatory=$true)] $ClientInformation ) $AdobeUsers = Get-AdobeUsers -ClientInformation $ClientInformation $Requests = @() foreach ($User in $AdobeUsers) { if (($null -eq $User.groups -or $User.groups.length -eq 0) -and ($null -eq $User.adminRoles -or $User.adminRoles.length -eq 0)) { #Account not used $Requests += New-RemoveUserRequest -UserName $User.username } } return $Requests } Export-ModuleMember -Function @( 'Import-PFXCert', 'ConvertTo-Base64URL', 'ConvertFrom-Base64URL', 'ConvertFrom-Base64URLToBase64', 'ConvertTo-JavaTime', 'New-ClientInformation', 'Get-AdobeAuthToken', 'Get-AdobeUsers', 'Get-AdobeGroups', 'Get-AdobeGroupMembers', 'Get-AdobeGroupAdmins', 'New-CreateUserRequest', 'New-RemoveUserRequest', 'New-UpdateUserRequest', 'New-RemoveUserFromGroupRequest', 'New-GroupUserAddAction', 'New-GroupUserRemoveAction', 'New-AddToGroupRequest', 'New-RemoveFromGroupRequest', 'Expand-JWTInformation', 'Send-UserManagementRequest', 'New-SyncADGroupRequest', 'New-RemoveUnusedAbobeUsersRequest' ) |