Active Directory – Set ‘Manager Can Update Membership List’ with PowerShell

AD group management usually is delegated in most organizations. Usually one of helpdesk’s responsibility or sometime a department manager decides who is member of her or his team at any given time. These users can be non-IT users in several situations.

To serve this purpose, a user can be designated as manager in the Managed By tab of the security group using Active Directory Users and Computers (ADUC) console. Placing a checkmark next to Manager can update membership list allows the user to update the group member by adding or removing users from the security group.

The Manager can update membership list option modifies the Access Control List (ACL) of the security group which we can see in the Security tab, in Advanced.

Setting the Managed by is fairly straight-forward. We can use the Set-ADGroup cmdlet to update the value. We can use the below code to update manager for a group:

$grpname = Read-Host "Enter AD Group's name"
$Managername = Read-Host "Enter AD user's name"
Get-ADGroup -Identity $grpname | Set-ADGroup -ManagedBy "$Managername"

But this doesn’t enable the Manager can update membership list option. To allow this user who is set as this group’s manager, we need to add an AccessRule for this user to the ACL of the group. I’m using this below process to put together a script,

In this below script, We get the user and current ACL of the group. And then the user who will be the manager. And to build the new ACL, we obtain the SID string, then set control type and AD permission. We also need to specify the System ID GUID of the Member attribute and this ACL need to be applied to this specific attribute (Member). Use all the variables to build a new rule, add the rule to the existing rule. And finally use Set-Acl cmdlet to apply new ACL to the Group. Yup!.. that easy!! πŸ€·β€β™‚οΈ

$grpname = Read-Host "Enter AD Group's name"
$Grp = Get-ADGroup -Identity $grpname
$GroupACL = Get-Acl AD:\$Grp

$Managername = Read-Host "Enter AD user's name"
$Manager = Get-ADUser -Identity $Managername
$UserSid = New-Object System.Security.Principal.NTAccount ($Manager.SamAccountName)

$Rights = [System.DirectoryServices.ActiveDirectoryRights]::WriteProperty
$Control = [System.Security.AccessControl.AccessControlType]::Allow
$Guid = [guid]"bf9679c0-0de6-11d0-a285-00aa003049e2"
$Rule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule ($UserSid, $Rights, $Control, $Guid)
$GroupACL.AddAccessRule($Rule)
Set-Acl -AclObject $GroupACL -path AD:\$Grp
Get-ADGroup -Identity $Grp | Set-ADGroup -ManagedBy "$Manager"
Write-Host $Manager.Name set as manager on $group.groupname

What if you have to update multiple groups with a user as manager to each. I didn’t have enough time to make a detailed one and the below script will serve the purpose. I’d probably include checks to make sure the group and the user exists in AD.

Note: csv file has groupname,managerSamname as column headers

$groups = import-csv "C:\Scripts\list.csv"

foreach ($group in $groups){
        $Grp = Get-ADGroup -Identity $group.groupname
        $GroupACL = Get-Acl AD:\$Grp
        $Manager = Get-ADUser -Identity $group.managerSamname
        $UserSid = New-Object System.Security.Principal.NTAccount ($Manager.SamAccountName)
        $Rights = [System.DirectoryServices.ActiveDirectoryRights]::WriteProperty
        $Control = [System.Security.AccessControl.AccessControlType]::Allow
        $Guid = [guid]"bf9679c0-0de6-11d0-a285-00aa003049e2"
        $Rule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule ($UserSid, $Rights, $Control, $Guid)
        $GroupACL.AddAccessRule($Rule)
        Set-Acl -AclObject $GroupACL -path AD:\$Grp
        Get-ADGroup -Identity $Grp | Set-ADGroup -ManagedBy "$Manager"
        Write-Host $Manager.Name set as manager on $group.groupname
}

Hope this post helped you in bulk setting group managers in AD.

Thank you for stopping by.✌

Amazon AppStream 2.0 – Increase Size of the Application Settings VHD

When we enable application settings persistence, the users’ Windows settings and application customizations are to a VHD file and is stored in a S3 bucket the same account we created the AppStream 2.0 stack. For every AWS Region, AppStream 2.0 creates a bucket in that account that is unique to the account and the Region. All application settings configured by the users are stored in the bucket for that Region.

There are no special configuration tasks needed to manage these S3 buckets as they are fully managed by the AppStream 2.0 service. The VHD file that is stored in each bucket is encrypted in transit using S3’s SSL endpoints and at rest using AWS Managed keys.

The buckets are named in a specific format:

appstream-app-settings-region-code-account-id-without-hyphens-random-identifier

The path for the folder where the settings VHD is stored in the S3 bucket uses the following structure:

bucket-name/Windows/prefix/settings-group/access-mode/user-id-SHA-256-hash
  • bucket-name = Name of the S3 bucket in which users’ application settings are stored
  • prefix = Windows version-specific prefix. Example v6 for Server-2016, Server-2019
  • settings-group = The settings group value from when we create the stack
  • access-mode = Identity method of the user
    • custom for the AppStream 2.0 API or CLI
    • federated for SAML
    • userpool for user pool users
  • user-id-SHA-256-hash = The user-specific folder name. Created using a SHA-256 hash hexadecimal string generated from the user ID

I use Notepad++ to determine the SHA-256 hash for a given user. When you have more than 1 user(😁) you’ll need to determine the user’s folder and this is an extra step that you need to go through.

To determine a user’s SHA-256 Hash using Notepad++:

  1. Click on Tools and SHA-256
  2. Click Generate

I leave the Treat each line as a separate string checked when I add multiple users. For a domain user, make sure the type the user ID in the UPN format, testuser@mydomain.com.

Note: This is case-sensitive. See screenshot for example.

The default VHD maximum size is 1 GB. There will be scenarios where the user requires additional space for application settings, we can download the users’ VHD to a Windows computer to expand it. Then, replace the current VHD in the S3 bucket with the expanded one.

Note: Don’t do this when the user has an active streaming session.

I have the TestUser01’s VHD that I’m going to download, expand and upload back to the S3 bucket.

  1. Locate and select the folder that contains the VHD
    • I used the SHA-256 hash generated earlier, copied it from Notepad++ to my clipboard and while in the S3 folder, I did a search or browser’s ctrl+f also works
  2. Download the Profile.vhdx file to a directory onto a Windows computer
    • Do not close the browser after the download completes
      • Easier to use the same session to upload the file back
  1. Open the command prompt as an administrator, and diskpart
  2. Type the following commands to select the vhd file and expand it
    • I’ve stored the VHDX file in C:\tmp\VHDs
select vdisk file="C:\tmp\VHDs\profile.vhdx"
expand vdisk maximum=2000
  1. Type the following Diskpart commands to find and attach the VHD, and display the list of volumes:
select vdisk file="C:\tmp\VHDs\profile.vhdx"
attach vdisk
list volume

The volume gets mounted as a drive and as you may notice, it is easier to determine the VHD with the volume label.

  1. Type the following command:
    • Corresponds to the number in the list volume output
    • In my case Volume 7
select volume ##
  1. Type the following command:
extend
  1. To confirm that the size of the partition on the VHD increased as expected
select vdisk file="C:\tmp\VHDs\profile.vhdx"
list volume
  1. To detach the VHD so that it can be uploaded
detach vdisk
  1. Return to the browser with the Amazon S3 console, choose Upload, Add files, and then select the enlarged VHD in file explorer
  2. Click Upload

The page shows upload progress,

Next time the user starts a streaming session from a fleet on which application settings persistence is enabled with the applicable settings group, the larger application settings VHD is available.

Kind of a related note that I learned while working with application settings persistence is, disabling application settings persistence or deleting the stack does not delete any VHDs stored in the S3 bucket. These VHDs must be deleted manually from the Amazon S3 console or API.

Hope you found this post useful in increasing the size of the application settings VHD in AppStream 2.0.

Thank you for stopping by.✌

Power BI – Create Visualizations with data from Active Directory

Power BI provides a wide variety of options to connect, analyze and visualize data from various sources. There were many instances where I’ve been asked to get a count of all users in the domain while in meetings and if possible a country-wise breakdown. Well..I don’t have that ready but would be nice to know if this information was needed earlier. As the user count is a moving target, I figured it’d be nice to have a PBI viz to help me answer this whenever asked.

There are several different ways to get this information and PBI viz is one of those.

In this post, I’ll go over steps on creating a visualization that I find useful to get a breakdown of users in the domain by country.

This should give you an idea on how to connect Power BI to AD and pull data to built visualizations.

To proceed further, make sure you have the Power BI desktop App downloaded and installed on your machine.

Launch Power BI Desktop,

  1. Click Get data and Click More…
  2. In the Get Data window, Click Other and Active Directory
  3. Click Connect
  1. Enter your Domain name under Domain then click OK
Enter domain name
  1. Enter credentials which has permissions to read attributes from AD and click Connect
Enter credentials
  1. The Navigator window shows all the tables available. In this post, I’m only going to use the data from user table
  2. Place a check mark next to user and click Transform Data
  1. In the Power Query Editor window, we can select the values we’ll be working with. As we can see, the query editor has detected what is known as Complex columns. The reason they are complex is that they actually contain an object, not just a simple value like a single line of text column.
  2. Click on Expand column icon
  3. Place a checkmark next to co
    • I’m also selecting c and countryCode for the sake of it, because why not! πŸ˜‰
  4. I’m also leaving the Use original column name as prefix checked
  5. Click OK
  1. I’m repeating the same steps for other columns as well to pick values I need
    • I’d need the UPN for unique values, so I’m picking that
Expand user
  1. Below screenshots shows all the columns I’ve selected to be loaded using Choose Columns, unselecting the columns I don’t need
  2. Once satisfied with the data, Click Close & Apply
  1. Data gets loaded into the model and depending on how many users you have in your domain and the hardware specs of the machine running PBI desktop, this can take a while

Below I have created a basic visualization which shows a pie chart with user breakdown by country name,

I did some formatting of the title, the legend and such to make it look pretty. If the data changes in AD, you can click on Refresh to get the updated information populated in the visualizations you create.

Here is another basic stacked column chart I created with UAC status of users per country. I created a UAC table which has the values for the UAC codes in AD and I merged those queries. I keep saying these are basic because by no means I’m a PBI expert but I’m very interested in learning and improving my skills in it every chance I get.

You can incorporate the visualizations you create, in a AD dashboard in PBI and If you have an on-premise PBI report server you can publish this report there or to PBI web.

Hope this post helped you in your AD visualizations journey.

Thank you for stopping by✌

Azure AD – Bulk Add Guest users using PowerShell

With Azure AD B2B collaboration, we can invite guest users into our tenant to allow them to access M365 apps and other Azure AD SSO integrated apps. There are multiple ways to invite external users into our Azure AD tenant. In this post, I’ll go through what I worked on recently to invite a bunch of external users in to one of the tenants I manage.

Make sure you are connected to Azure AD,

$credential = Get-Credential
Connect-AzureAD -credential $credential

To send an invite to an external user:

$GuestName = Read-Host "Enter name of user being invited"
$GuestEmail = Read-Host "Enter email address of user being invited"
New-AzureADMSInvitation -InvitedUserDisplayName $GuestName -InvitedUserEmailAddress $GuestEmail -SendInvitationMessage $True -InviteRedirectUrl "http://myapps.microsoft.com"

To bulk invite users from a csv file, this below script will work. This script checks to make sure if the user is already invited and also includes a custom message you can include in the invite.

How the csv file looks like,

$GuestUsers = Import-csv "C:\tmp\InviteGuestUsers\GuestUsers.csv"

$invitationBody = @"
Hi,

Please accept this invitation to join our organization.
If you have any questions, please contact our helpdesk at
support@internaldomain.com

"@

$invitemessage = @{customizedmessagebody = $invitationBody}

ForEach($GuestUser in $GuestUsers) {

$GuestUserEmail = $GuestUser.GuestEmail
$GuestUserName = $GuestUser.GuestName

    if ((Get-AzureADUser -SearchString $GuestUserEmail).Length -le 0) {

        $Invite = New-AzureADMSInvitation -InvitedUserDisplayName $GuestUserName -InvitedUserEmailAddress $GuestUserEmail -SendInvitationMessage $True -InvitedUserMessageInfo $invitemessage -InviteRedirectUrl "http://myapps.microsoft.com"
        Write-Host "Guest user $GuestUserName invited" -ForegroundColor Green
        } else {
        $status = Get-AzureADUser -filter "Mail eq '$GuestUserEmail'" | Select -Expandproperty UserState
        Write-Host "Guest user $GuestUserName already invited - Guest account exists in tenant and invite status is $status" -ForegroundColor Red
        }
}

To list all guest users in the tenant and their invitation acceptance status:

Get-AzureADUser -filter "UserType eq 'Guest'" | Select DisplayName,UserPrincipalName,UserState

or a filter can be applied to determine a specific user,

$guestuser = Read-Host "Enter the guest user email address to check invite status"
Get-AzureADUser -filter "Mail eq '$guestuser'" | Select DisplayName,UserPrincipalName,UserState

Hope this post helped you in external user invites.

Thank you for stopping by. ✌

AWS – AppStream 2.0 Implementation Guide – Part II – Updated

This is a continuation of my earlier post here – AWS – AppStream 2.0 Implementation Guide – Part I – Updated

In this post, I’ll cover the steps that come in after creating an image in AppStream 2.0.

Provision a fleet

A fleet defines the streaming instances which is the underlying hardware, network, Active Directory (if applicable), and scaling configuration for the application streaming infrastructure we are going to deploy.

To create a fleet:

  1. Login to AppStream 2.0 console (https://console.aws.amazon.com/appstream2)
  2. In the left navigation pane, choose Fleets, Create Fleet
Create Fleet
  1. In Step 1: Provide Fleet Details, fill the below information and choose Next
    • Name = Unique name identifier for the fleet
    • Display Name = A friendly name displayed in the console
    • Description = An optional description for the fleet
    • Tags = Provide necessary tags
Step 1: Provide Fleet Details
  1. In Step 2: Choose an image, I’m picking the image I created in my earlier post. I filter it by Private to make it easier. and then choose Next
Choose an image – filter by private
  1. For Step 3: Configure fleet,
    • In Choose instance type, we define the hardware configuration for each of the instances that make up your fleet. Because I created the image by using the Graphics Design family, that instance type is already populated
    • Assuming I had picked General Purpose family while creating the image, other instance type options will also be presented
      • Instance Type = Pick the instance type. I’m picking stream.graphics-design.xlarge for this exercise
      • Fleet Type details = Always-on or On-Demand. I’m picking On-Demand
        • Always-on
          • Instances run all the time, even when no users are streaming applications. When this option is selected, instances are immediately available for the next user to connect to immediately
          • All instances that are running are charged the applicable running instance fee, based on the instance type and size, even when users aren’t connected
        • On-Demand: Instances run only when users are streaming applications. Idle instances that are available for streaming are in a stopped state. When this option is selected, a user must wait for one to two minutes for an instance to start up
          • Instances are charged applicable running instance fee, based on the instance type and size, only when the instances are used for streaming sessions
          • Instances in On-Demand fleets that are not being used for streaming sessions are charged a small hourly stopped instance fee that is the same for all instance types and sizes
      • User session details = I’m sticking to the default values but in a production environment, you should determine this after discussing with your IT Security and Compliance team. Or maybe you have a organizational policy defined for this
        • Maximum session duration = how long user streaming sessions can remain active
        • Disconnect timeout = how long user streaming sessions can remain active after users are disconnected
        • Idle disconnect timeout in minutes = how long user can be idle (inactive) before they are disconnected from their streaming session
      • Fleet Capacity = For this exercise, I’m defining Minimum capacity to 1 and Maximum Capacity to 2
        • Minimum capacity = The minimum number of users who are expected to be streaming at the same time
        • Maximum capacity = The maximum number of users who are expected to be streaming at the same time
Step 3: Configure fleet
  • Stream view = I’m choosing Application
    • Application = Displays only the windows of applications opened by users
    • Desktop = Displays the standard desktop that is provided by OS
  • Scaling details (Advanced) = I’m adding 1 instance when the capacity reaches 75% and removing 1 instance when the capacity goes down to 25%
    • Specify the scaling policies that AppStream 2.0 uses to increase and decrease the capacity of your fleet
    • Remember that the size of the fleet is limited by the minimum and maximum capacity we’ve specified earlier
Stream view and Scaling details (Advanced)
  • IAM role (Advanced) = I haven’t created an IAM role and I’m leaving this option as is
  1. Click Next
  1. In Step 4: Configure Network,
    • Default Internet Access = I’m leaving this option checked for this exercise
      • Important Note: You wouldn’t want this in a production environment. Depending on how your network infrastructure is configured, it is preferred either to route the traffic via a NAT gateway or through a web filtering system
    • VPC = I’ve picked the default VPC
    • Subnet 1 = The first available subnet
    • Subnet 2 = The second available subnet
    • Security group(s) = I’ve picked the default
      • This wouldn’t be recommended in a production environment. You’ll access which resources needs access to which ports and services if you have direct connect or if the resources in this VPC are connecting to resources that live on other VPCs
    • Active Directory Domain (Optional) = I don’t have an AD domain to integrate but I’m planning to cover this in a later post
  2. Click Next

  1. In Step 5: Review, Confirm the fleet configuration details. To change settings for any section, choose Edit, and make the needed changes. After you finish reviewing the configuration details, choose Create
  2. In the pricing acknowledgement dialog box, select the acknowledgement check box, and Click Create to begin provisioning your fleet with the initial set of running instances
pricing acknowledgement dialog box

Note: If an error message that you don’t have sufficient limits to create the fleet, don’t panic it’s not you, it’s them. 😁 Submit a limit increase request to the AWS Support Center.

You can check your allocated quota for AppStream of other AWS services in Service Quotas and clicking on AWS Services and searching for the service

AWS services in Service Quotas

In the AWS support center, to request quota increase,

AWS support center

If all goes well, you’ll see a success prompt that your fleet is bein created,

fleet creation success

Fleet provisioning usually takes 10 minutes to finish. While your fleet is being created and fleet instances are provisioned, the status of your fleet displays as Starting in the Fleets list. Choose the Refresh icon periodically to update the fleet status until the status is Running

fleet running

Create a stack and a streaming URL

A stack consists of a fleet, user access policies, and storage configurations. We create a stack to start streaming applications to users.

To create a stack:

  1. Login to AppStream 2.0 console (https://console.aws.amazon.com/appstream2)
  2. In the left navigation pane, choose Stacks, Create Stack
Create Stack
  1. In Step1: Stack Details, provide below information and Click Next
    • Name = unique name identifier for the stack
    • Display Name = name displayed in the console
    • Description = Option description text
    • Redirect URL = An optional URL redirect users at end of their streaming session
    • Fleet = Fleet we created earlier
    • Tags = Choose Add Tag and add necessary tags
    • VPC Endpoints (Advanced) = Internet. We can create a private link, which is an interface VPC endpoint, in our virtual private cloud
    • Embed AppStream 2.0 (Optional) = optional webpage option to embed AppStream session

  1. In Step 2: Enable Storage, pick an option that suits you and click Next
    • For this exercise I’m not picking any of these options
    • Persistent storage can be provided for our users by choosing on of these options
      • Home Folders = A S3 bucket is provisioned where users can save their files to their home folder and access it during application streaming sessions
      • Google Drive for G Suite = Users can link their Google Drive for G Suite account to AppStream 2.0. During application streaming sessions, they can sign in to their Google Drive account, save files to Google Drive, and access their existing files in Google Drive. Personal Gmail accounts not allowed
      • OneDrive for Business = Users can link their OneDrive for Business account to AppStream 2.0. During application streaming sessions, they can sign in to their OneDrive account, save files to OneDrive, and access their existing files in OneDrive. Personal OneDrive accounts not allowed

  1. In Step 3: User Settings, configure the following settings. When you’re done, click Review
    • For this exercise, I’m picking the most restrictive options but these will usually depend on your DLP policies. Would be a good idea to consult with your IT security and compliance team on this
      • Clipboard, file transfer, print to local device, and authentication permissions
        • Clipboard = By default, users can copy and paste data between their local device and streaming applications
        • File transfer = By default, users can upload and download files between their local device and streaming session
        • Print to local device = By default, users can print to their local device from within a streaming application
        • Password sign in for Active Directory = Users can enter their AD domain password to sign in to an AppStream 2.0 streaming instance that is joined to an AD domain
        • Smart card sign in for Active Directory = Users can use a smart card reader and smart card connected to their local computer to sign in to an AppStream 2.0 streaming instance that is joined to an AD domain
      • Application settings persistence options
        • Enable Application Settings Persistence = Users’ application customizations and Windows settings are automatically saved after each streaming session and applied during the next session. These settings are saved to an Amazon S3 bucket
        • Settings Group = The settings group determines which saved application settings are used for a streaming session from this stack. Let’s say we apply this same settings group to another stack, both stacks use the same application settings
User Settings
  1. In Step 4: Review, Confirm the stack configuration details. To change the settings for any section, choose Edit and make the necessary changes. After reviewing the configuration details, Click Create

Create a Streaming URL

To test application streaming without setting up users, we can create a temporary URL that can be pasted into a browser window.

  1. In the left navigation pane, choose Stacks
  2. For Stacks, select the stack we just created
  3. Choose Actions, Create streaming URL
Create Streaming URL
  1. In the Create streaming URL dialog box, provide User id and URL expiration, Click Get URL
    • This streaming URL is purely for testing purposes
    • In a production environment, we usually have other authentication and authorization methods to allow access to our users to the designated resources. I’ll cover the steps for enabling Federation with Azure AD Single SSO and AppStream 2.0 in an upcoming post
create test user
  1. In a browser, browse to the streaming URL. AppStream 2.0 displays an application catalog page that lists the applications that you have configured for streaming
App Catalog in browser

Here is Blender via AppStream in a browser,

Blender via AppStream in a browser

and here is Blender via the AppStream client,

Blender via AppStream client

Manage user access

AppStream 2.0 user pool is a built-in identity management feature that we can use to enable users to access their streamed applications.

Note: Like I mentioned earlier, in a production environment, we’d use SAML 2.0 to federate through AD or any other custom identity solution provider(Example: Azure AD) that supports SAML 2.0

To enable users in the user pool to open applications after they sign in to the AppStream 2.0 user portal, we must assign each user to at least one stack that contains applications. After we assign the user to a stack, AppStream 2.0 sends an optional notification email to the user with instructions about how to access the stack and a URL. The user can access the stack by using the URL until we delete the stack or unassign the user from the stack.

Add users

To add users:

  1. Login to AppStream 2.0 console (https://console.aws.amazon.com/appstream2)
  2. In the left navigation pane, choose User Pool, Create User

Note: Remember, along with fee on the instances, there is an Users fee charged monthly. For each end user who launches a streaming session on a fleet instance there is a fee of $4.19 for the month in which the streaming session occurred.

Create User
  1. In the Create User dialog box, provide Email, First Name & Last Name information and choose Create User
  2. The User Pool list refreshes, and the user we added is listed and enabled

Assign a stack to the user

  1. In the left navigation pane, choose User Pool, and select the user we created
  2. Choose Actions, Assign Stack
  3. In the Assign Stack dialog box, for Stack, I’ve selected the stack that I created earlier
  4. I’m leaving the Send email notification to user option selected
  5. Choose Assign Stack
  6. AppStream 2.0 sends an email to the address we specified for the user
  7. User can open the Login Page link in the notification email to login and access applications via AppStream 2.0

I’m aware this was a lengthy post but I hope this helped you out in your AppStream 2.0 deployment. As I mentioned earlier, I’ll add another post on how to enable federation with Azure AD SSO and Amazon AppStream 2.0.

If you were following along and if it is a test environment, remember to stop your fleet. Else, you’ll incur charges.

Thank you for stopping by. ✌