Category Archives: PowerShell

Bulk Assign Licenses in Office 365 Using PowerShell

If you manage an Office 365 tenant, you are probably familiar with assigning licenses to provision services for users. That process is pretty straightforward for a single user.


But how do you do it for a hundred or thousand people in your organization? PowerShell.

First, you will need to connect to Office 365 via PowerShell. If you haven’t done this before, follow these steps to install the prerequisites.

To connect to O365/MSOnline, use the following command:

Import-Module MSOnline

You will be prompted for credentials – this needs to be a user with at least user management role permissions, but most operations in this module will require global admin permissions.

Next, you will need to get a list of licenses available in your tenant. This can be viewed easily in the admin portal under Billing, but is identified by the AccountSkuID in PowerShell. To generate a list of what is available and assigned, run the following command:


The results will contain your tenant name and sku and looks something like this:


If you’re using E1/E3 licenses, they will have a name like “tenantname:ENTERPRISEPACK” or “tenantname:STANDARDPACK”.

Now that you know what you have available to assign, you need to determine which users will be assigned a license. This can be a difficult task, especially in larger organizations.

If you’re lucky enough to just assign all users in your tenant a license, your process will be relatively simple. Prior to assigning licenses, you must assign a location. This is a required field and is done by country. This will essentially provision the Exchange Online mailbox in the proper region and ensure that it follows all local laws, etc.

To assign the US location to a single user, you would use the following command:

Set-MsolUser $upn -UsageLocation US

All countries follow the 2-letter ISO code standard – a list of those can be found here.

Now, we’re using PowerShell – we want to actually bulk assign licenses and locations, not just do single users. To assign the US location to all of your tenant users, use the following command:

Get-MsolUser -All | Set-MsolUser -UsageLocation US

To verify the results, use the following command:

Get-MsolUser -All | Select DisplayName,UsageLocation

Once the location is assigned either through the admin portal or PowerShell, you can assign licenses. The following command would assign an E3 license to all users in the US only:

Get-MsolUser -All -UsageLocation ‘US’ | Set-MsolUserLicense -AddLicenses “tenantname:ENTERPRISEPACK”

There are several other properties that may be useful in narrowing down the scope of users to bulk assign licenses to. Use the following command to view only users that do not have a license assigned:

Get-MsolUser -UnlicensedUsersOnly

This command will assign licenses only to users with a specific domain name:

Get-MsolUser -All -DomainName ‘’ | Set-MsolUserLicense -AddLicenses “tenantname:ENTERPRISEPACK”

A full list of properties to use with Get-MsolUser can be found here.

What if it isn’t this straightforward in your organization? You may have several countries, types of licenses, or maybe you want to assign licenses in batches. Sometimes it’s just easiest to assign both the location and license at the same time from a CSV file – this is usually the preferred method in larger organizations. This operation can be done with a simple PowerShell script (download it here):


The above script references users in a CSV file containing users’ UPN, location, and license to assign. It looks like this (download it here):


You will need to modify the script to use the correct path to the CSV file.

If you need to generate a list of users in your O365 tenant, including their UPN, location, and whether or not a license is currently assigned, you can use the following command:

Get-MsolUser | select-object DisplayName,UserPrincipalName,UsageLocation,IsLicensed

Your results will look similar to this:


To export the same data to a CSV file, add a bit more to the end:

Get-MsolUser | select-object DisplayName,UserPrincipalName,UsageLocation,IsLicensed | export-csv C:\pathtofile\o365export.csv -notype

ConfigMgr PowerShell Cmdlet Library Now Available

systemcenter_logo_smallMicrosoft has released the Cmdlet Library for System Center Configuration Manager. The library will stay up-to-date with Microsoft to provide the latest cmdlets available.

The ConfigMgr Cmdlet library can be downloaded here:

Blog article from the ConfigMgr team is here:

Additionally, here are some examples of these scripts in action:

How To Upload and Run a Windows 10 Enterprise VM in Azure

Running a workstation OS in the cloud may not be the most practical solution at this time, but it may prove useful in some test lab scenarios. While Azure does support plenty of server OS options that you can choose from a gallery and have up and running within minutes, Windows 7 and 8 images are currently only available to MSDN Subscribers. Azure does provide the capability to upload your own VHD to run on their platform, though. In this guide, we will create a Hyper-V VM with Windows 10 Enterprise Preview, prepare the VHD and upload it to Windows Azure, and connect to the Windows VM for use in the cloud. We will be using Windows 10 in this guide, but the steps are the same for Enterprise versions of Windows 7 and Windows 8.

First, you should know that there are a few catches. This is not supported by Microsoft at all, so don’t expect any help from them if you need to open a case. No worries- we’re all IT enthusiasts, here. Also, whichever version of Windows that you choose for use in Azure needs to be the Enterprise version. If you try to upload Windows 7 Ultimate or Windows 8.1 Pro for example, Azure will not prepare the VM properly and it will get stuck in a provisioning state. This happens because Azure uses a specific unattend.xml file on the backend for VM deployment, which you don’t have access to. Second, Azure is not cheap. I have a test lab environment that I use in Azure because of how easy it is to access from anywhere without needing any hardware, and I like to get my hands dirty with Azure. That being said, I always leave my VMs turned off unless I am using them. Be sure to shut down your VMs from the Azure portal, and not from within the OS itself, or you will still be charged for uptime! There are PowerShell scripts available to properly spin down Azure systems– I’d recommend looking into these for any production environments. This is server grade hardware, so it can cost you hundreds to thousands of dollars each month if you’re not careful. I’d recommend using the Azure Pricing Calculator to get a good idea of what it will cost. I’d also recommend setting up the free trial of Azure that comes with $200 to spend on its services- more than enough to get you up and running in this guide. This guide also assumes some level of Azure proficiency- if you are not familiar with Azure, I highly recommend using this Test Lab guide from Microsoft to get up and running.

To begin the process, we will create a VM in Hyper-V. I am using the Hyper-V feature in Windows 8.1, but any version of Hyper-V will do. Before you create the VM, save yourself some work later and create a VHD to run the VM on since Azure requires that format. You can convert a VHDX drive to VHD drive, but it’s much less work to do it correctly front. By default, Hyper-V in Windows 8 and Server 2012 uses the VHDX format. Another requirement of Azure is using a fixed/static VHD size, and not a dynamically expanding size, which most VMs default to now. Lastly, the VM needs to be an integer- no decimals in the VHD size.

In Hyper-V Manager, create a new Virtual Hard Disk and choose the VHD format.


Choose a fixed size VHD.


Use an integer for the VHD size. I’d recommend using 20GB as a minimum. Azure will automatically expand the size to whatever performance tier you use for the VM later.


Now, create a new VM from Hyper-V Manager.


If presented with the option, choose to create a Generation 1 VM. The other specifications don’t matter, but give it an appropriate amount of memory and a connection to the Internet if you are patching the system.


When asked, specify to install the OS on the VHD we already created.


Now, mount the ISO for your Enterprise edition of Windows and proceed to install the OS.


When the VM boots up and you are greeted with the Windows Setup screen, hit SHIFT + F10 to bring up a command prompt. This step is optional, but it will prevent Windows from creating a recovery partition, which is useless in Azure.

The commands used to properly format the disk for installation are:

  • Diskpart
  • Select Disk 0
  • Clean
  • Create Partition Primary
  • Format Quick FS=NTFS
  • Active
  • Assign


Now, proceed with the install as normal. Accept the EULA, choose the custom installation option, and install on the available partition.


Proceed with the installation, allowing the system to reboot as necessary.


When the Installation gets to the Settings screen, do not proceed as usual. When you see the settings screen, hold CONTROL + SHIFT + F3 at the same time on your keyboard. This will force Windows setup to enter Audit Mode, which is specifically made for capturing images. This does a couple things- it will skip the personalization steps built into Windows 7 and greater, and it will log you in automatically as the administrator without creating a user account.


Windows will reboot and automatically log in as the administrator. You will see a window pop up for System Preparation every time Windows boots- this is OK. Close it for now- we will run it on our own later.


Now, patch Windows and install any applications that you want to be present on your VM. If using Windows 10 Preview, you may want to check if any newer builds are available in PC Settings.


Now is also a good time to add an additional local administrator account to the VM. We will use this account to RDP into the system once it is running in Azure. This isn’t always necessary, but in my experience it has been required for the Windows 10 Preview. Be sure to remember the username, set a secure password (it will be directly accessible in the cloud), and add the user to the Administrators group on the local system.


When Windows is patched and in your desired state for capture, launch Run, and type in “sysprep”. This will open the directory containing the Sysprep executable.


Run Sysorep.exe.


In the Sysprep options, choose the OOBE, check the box to Generalize, and choose to shutdown the system when finished.


Sysprep will now run and prepare the image to be used for deployment. When finished, the VM will be turned off.


From here, you can delete the VM in Hyper-V – we only need the VHD file that the OS was installed on. Copy the VHD somewhere convenient, but do not launch it in a VM, or you will need to repeat the Sysprep steps.

We will now prepare Azure to receive your new VHD file. If you don’t have a small test lab configured yet in Azure, you may want to follow this guide from Microsoft to get up and running first. At the very least, you will need a Cloud Service, Storage Account, and Virtual Network configured.

To create a new storage service in Azure (if you don’t have one already), choose New on the bottom menu, choose Data Services, then Storage. Choose Quick Create, and name your URL something unique. Choose a region that is close to you, also.


Now, choose your new Storage from the left. In this example, mine is called “hefflab”.


Create a new Container in your Storage to hold the VHD we will be uploading. Choose Containers, then choose Add.


Name your Container something like VHD, since that’s what we’ll be using it for.


Your new Container should now be visible under Storage.


We will use PowerShell for the remaining operations to upload the VHD. If you haven’t installed the Azure PowerShell Module yet, do that first. When finished, launch Microsoft Azure Powershell module. Use Add-AzureAccount to connect this PowerShell session with your Azure account.


Once authenticated to your Azure account, use the following command to download your Publish Settings File:



This will open a browser and download a file named after your Azure subscription that ends in “publishsettings”. Save this somewhere close. Now, we will import this file into your current PowerShell session using the following command:

Import-AzurePublishSettingsFile <Path To PublishSettings File>


Next, we need find the URI path to your container to send the VHD file. You can see this under the Container view on the Azure portal. It will look something like this:


Now, use the following command to upload the VHD into Azure. The Destination is your container name plus the name of your new VHD file. The LocalFilePath is where the VHD currently resides on your local system. Be patient- this cane take some serious time.

Add-AzureVhd -Destination <Container URL/VHD> -LocalFilePath <path to local VHD>

2015-01-19_14-38-38Grab some coffee. This PowerShell command will actually skip empty space in the VHD, but definitely do this where you have some good upstream bandwidth.


When complete, your PowerShell module should look like this:


Now we will create a Virtual Machine Image from the uploaded VHD in the Azure portal. Go to the Images tab of the Virtual Machines section. Choose to create an image.


Fill in the name for your VM image and browse your container to find the uploaded VHD. Check the box indicating that you ran Sysprep on the machine, also.


The image will now be listed under OS images.


Using the New button on the lower menu, choose to create a new Virtual Machine from Gallery.


The Windows 10 x64 Enterprise image is now available to deploy a VM from.


From here, you can customize the VM as desired, but be sure to read up on Azure pricing! The virtual machine will launch and take a bit of time to provision, but you should be able to RDP into it by using the Connect button on the bottom menu.


When prompted for credentials, you can try either the account you used when deploying the VM in Azure, or you can use the local administrator account that we created right before capturing the VHD. You may need to enter the computer name has the domain, such as hostname\localadmin.


And from here, it should work just like a standard RDP session.


I hope this post was helpful! Leave a comment if I can answer anything for you.