Wednesday, 16 January 2019

Extract Office 365 License information for all users using Powershell

 

 

This script gathers O365 license information for all active users.  It will populate fields within a csv for import into Excel which includes UPN, Licenses, whether it is a shared mailbox or not and whether or not the user is blocked.

 

A separate row will be created for each license, with the user’s UPN detailed on each row.  Once the export is complete, you can filter this list in excel to get whichever granular information you need.

 

 

$LogFilePath = $env:LOCALAPPDATA + "\Cloudwyse\Logs\user_license_report_" + $(get-date -Format ddMMyy_HHmmss) + ".log"

Start-Transcript -Path $LogFilePath -NoClobber

$365Pass = cat C:\cloudwyse\securestring365.txt | convertto-securestring

$365Cred = new-object -typename System.Management.Automation.PSCredential -argumentlist "admin@contoso.onmicrosoft.com",$365Pass

$DateTime = (Get-Date -Format "ddMMyyyy-HHmmss")

 

$365Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $365cred -Authentication Basic -AllowRedirection

Import-PSSession $365Session

Connect-Msolservice -Credential $365Cred

 

 

Write-Host  -ForegroundColor Magenta "Pulling mailbox information for all users, please be patient..."

$JobStart = Get-Date

$getmailbox = get-Mailbox

$JobEnd = Get-Date

$JobSecondsTaken =($JobEnd - $JobStart)

Write-Host  -ForegroundColor Yellow "Extract complete.  The Job took" $JobSecondsTaken.Seconds "seconds."

$total = $null

$Job2Start = Get-Date

$userList = @()

foreach ($user in $getmailbox) {

    $lookup = get-msoluser -userprincipalname $user.userprincipalname

    Write-Host  -ForegroundColor Magenta "Current user is" $user.userprincipalname

    $licenses = $lookup.licenses

    foreach ($license in $licenses) {

        $us = New-Object PSObject

        $us | Add-Member -type NoteProperty -Name 'UPN' -Value $lookup.userprincipalname

        $us | Add-Member -type NoteProperty -Name 'License' -Value $license.accountskuid

        $us | Add-Member -type NoteProperty -Name 'IsShared' -Value $user.IsShared

        $us | Add-Member -type NoteProperty -Name 'Blocked' -Value $lookup.BlockCredential

        Write-Host  -ForegroundColor Cyan $license.accountskuid "was added to the list for" $lookup.userprincipalname

        $userList += $us

        }

    $total = $total +1

   

    }

$Job2End = Get-Date

$Job2SecondsTaken =($Job2End - $Job2Start)

Write-Host -ForegroundColor Yellow "$total users processed in" $Job2SecondsTaken.Minutes "minute(s) and" $Job2SecondsTaken.Seconds "second(s)."

Remove-PSSession $365Session

$userlist | export-csv C:\Cloudwyse\user_license_report$datetime.csv

Write-Host -ForegroundColor Yellow "Report exported to C:\Cloudwyse\user_license_report$datetime.csv"

 

 

Stop-Transcript

 

 

 

I’m happy to post the script as a text file if that will help anyone.

 

 

 

Wednesday, 19 December 2018

Windows 10 NLA Public vs Private profiles - what's the difference?

In a recent post I described how I used Powershell to configure a dual-homed Radius server where I wanted to firewall everything on the DMZ interface but not affect the production interface.  I did this using a Windows feature known as NLA – Network Location Awareness – which has been around in one form or another since Windows XP, although many people still know very little about it.
NLA in Windows 10 uses 3 different network profiles: Domain, Public and Private.  Windows assigns the network connection to one of these profiles when a new network is discovered.  It’s important to know the differences because this actually provides us with a really powerful tool to lock down our machines using the built in Windows Firewall.

How the appropriate location is determined

Domain

Microsoft explain that Windows checks the connection specific DNS name against “HKEY_Local_Machine\Software\Microsoft\Windows\CurrentVersion\Group Policy\History\NetworkName” (although on my test machine this was an empty key but “HKEY_Local_Machine\Software\Microsoft\Windows\CurrentVersion\Group Policy\History\MachineDomain” contained the domain DNS name).  If this matches and the machine is able to go on and contact a Domain Controller via LDAP, then you are assigned the Domain profile.

Public vs Private

This is the bit most people get confused about and it is a distinction which appeared from Windows Vista onwards (in XP the profiles were Domain and Standard).  The way that the location is determined is via the prompt that you receive when connecting to a new network ie “Do you want to allow your PC to be discoverable by other PCs and devices on this network?”.  Selecting “Yes” assigns the Private profile whilst “No” assigns the Public profile.

It’s useful to know of this distinction as it will allow you to configure specific rules on the firewall which will behave differently depending on whether you are connected to a trusted or untrusted network.

Wednesday, 12 December 2018

Connect to O365 exchange with powershell using session import

 

It seems fairly obvious but a lot of people are unsure how to import a remote powershell session to O365. Simply do the following:

 

 

$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $UserCredential -Authentication Basic -AllowRedirection

Import-PSSession $Session

 

 

 

Friday, 30 November 2018

Disable inbound advanced firewall rules on public interface only with Powershell for a Windows Radius/NPS server

 

 

Recently I built an NPS server for Radius authentication, and had to dual home it with one NIC in the DMZ and one on the production network.  I wanted to firewall everything on the DMZ interface but not affect the production interface.  That way I could then allow the traffic I wanted to enable on the DMZ interface port by port.  Assuming windows has correctly detected the profile on the two interfaces as “Domain” and “Public”, which it should based on the resources visible on each network, you can run the following script to disable traffic just on the public interface.

 

 

 

$LogFilePath = $env:LOCALAPPDATA + "\Cloudwyse\Logs\adv_firewall" + $(get-date -Format ddMMyy_HHmmss) + ".log"

Start-Transcript -Path $LogFilePath -NoClobber

 

$rules = Get-NetFirewallRule

$total = 0

foreach ($rule in $rules) {

if (($rule.Profile -like "any" -or $rule.Profile -match "public") -and $rule.enabled -like "True" -and $rule.direction -like "Inbound") {

if ($rule.Profile -like "any") {

  Set-NetFirewallRule -Name $rule.Name -Profile "Domain, Private"

  write-host "Setting" $rule.DisplayName "Domain, Private" }

elseif ($rule.Profile -match "Domain" -and $rule.Profile -match "private" -and  $rule.Profile -match "public" ) {

  Set-NetFirewallRule -Name $rule.Name -Profile "Domain, Private"

  write-host "Setting" $rule.DisplayName "Domain, Private" }

elseif ($rule.Profile -match "Domain" -and  $rule.Profile -match "public" ) {

  Set-NetFirewallRule -Name $rule.Name -Profile "Domain"

  write-host "Setting" $rule.DisplayName "Domain" }

elseif ($rule.Profile -match "Private" -and  $rule.Profile -match "public" ) {

  Set-NetFirewallRule -Name $rule.Name -Profile "Private"

  write-host "Setting" $rule.DisplayName "Private" }

elseif ($rule.Profile -like "public" ) {

  Disable-NetFirewallRule -Name $rule.Name

  write-host "Disabling" $rule.DisplayName }

else {write-host -ForegroundColor Red "Error - check logs"}

$total = $total +1  }}

write-host -ForegroundColor Yellow "$total rules processed"

 

stop-transcript

 

 

 

 

Monday, 19 November 2018

Very Simple Powershell Ping test or IP scanner script

 

 

This simple Powershell script will carry out a quick check against each IP in a 24 bit subnet and return a value of true or false dependent on whether or not it receives a reply.  It’s similar to using an IP scanner or a ping script.

 

 

$subnet = "10.20.6."

1..254 | Foreach-Object {write-host "$Subnet$_..." (Test-Connection -ComputerName "$Subnet$_" -Quiet -Count 1 ) }

 

 

It’s simple and does the job as it is however you could obviously make it more fancy by exporting to csv or an array or emailing the output etc etc.

 

 

Wednesday, 17 October 2018

O365 - reverting hard matching migration using ImmutableID

 

This is a very obscure problem, so I’m recording this more for my own reference in future rather than expecting anyone else to have the same issue!

The issue occurs when a migration from a hybrid exchange domain to another domain which uses AD Sync has been completed in the following manner:

1.    filter/delete user in current domain

2.    AD Sync soft deletes mailbox

3.    Create user in new domain (in a filtered OU that won’t be synchronised)

4.    Obtain new account GUID and convert to immutableID string (base64)

5.    Undelete mailbox (mailbox becomes cloud mailbox)

6.    Assign ImmutableID to mailbox (from the target account)

7.    Move target account to a synchronised OU then allow AD sync to hard match the accounts

8.    For some reason, there is a need to reverse this migration.  So filter/delete user in new domain

9.    AD Sync soft deletes mailbox

10. Re-create or unfilter user in old hybrid domain

11. Obtain account GUID and convert to immutableID string (base64)

12. Undelete mailbox (mailbox becomes cloud mailbox)

13. Assign ImmutableID to mailbox (from the original account) using the command

  

Set-MsolUser -UserPrincipalName "<UPN>" -ImmutableId "<ImmutableID>"

 

 

At this point the following error is received:

 

Set-MsolUser : Uniqueness violation. Property: SourceAnchor.

At line:1 char:1

+ Set-MsolUser -UserPrincipalName user@domain.com  -Immutableid

 

 

The fix is to run…

 

 

Get-MsolUser -ReturnDeletedUsers | select-object UserPrincipalName,Immutableid,objected

 

 

Find the user with the ImmutableID matching the one you are trying to assign

 

 

Remove-MsolUser -objectID "<objectID>" -RemoveFromRecycleBin

 

 

Then you should be able to run

 

 

Set-MsolUser -UserPrincipalName "<UPN>" -ImmutableId "<ImmutableID>"

 

 

…if you still have a problem, find the user’s objectID with

 

 

Get-MsolUser -userprincipalname "<UPN>" | select-object UserPrincipalName,Objectid

 

 

And run…

 

 

Set-MsolUser -objectid "<objectID" -ImmutableId "<ImmutableID>"