Powershell: Monitor LAPS

LAPS is Microsoft’s “Local Administrator Password Solution” and is a hot topic when talking about cyber security and what measures to take, when fighting the cyber criminals. Read more about LAPS here.

This is just something short and sweet, and a very simple powershell script to monitor and read all computer objects in specified OUs in Active Directory, read the relevant attributes of the object, and if LAPS attributes are empty (hence no LAPS active), then list the objects in a list and send it as an email.

You can run the script on a schedule using Task Scheduler, and this way monitor which computers in your Active Directory that’s missing LAPS.

<#
.DESCRIPTION
This scripts runs through all computer objects in specified OUs. If ms-Mcs-AdmPwdExpirationTime is empty, return to list and send email containing the list.

.AUTHOR
Martin Bengtsson
#>

try {
    Import-Module ActiveDirectory -ErrorAction Stop -Verbose:$false
} catch {
    Write-Error "Active Directory module failed to Import. Terminating the script. More details : $_"
    exit(1)
}

#Email SMTP variables
$AnonUsername = "anonymous"
$AnonPassword = ConvertTo-SecureString -String "anonymous" -AsPlainText -Force
$AnonCredentials = New-Object System.Management.Automation.PSCredential($AnonUsername,$AnonPassword)
$SMTPServer = "INSERT YOUR SMTP SERVER”
$To = "INSERT RECIPIENTS"
$From = "Active Directory Monitor <SENDER@SENDER.COM>"
$Subject = "Computers (Servers) Missing LAPS Password"

$OUs = "CN=Schema,CN=Configuration,DC=EUROPE,DC=TEST,DC=CONTOSO,DC=COM"

#Loop through all computers in specified OUs. Also filtering on OU, OS and LAPS password already set
$Computers = ForEach ($OU in $OUs) {
Get-ADComputer -SearchBase $OU -SearchScope 'Subtree' -Filter * -Properties * | Where-Object {($_.DistinguishedName -notlike "*OU=Inactive,OU=Servers*") -AND ($_.'ms-Mcs-AdmPwdExpirationTime' -eq $null) -AND ($_.OperatingSystem -like "Windows Server*")} | Select-Object Name, ms-Mcs-AdmPwdExpirationTime, OperatingSystem
}

$Count = $Computers.Count
Write-Host -ForegroundColor Yellow "Count is" $Count
$Body = "<b>Following computers has no LAPS-password stored in Active Directory and are therefore not protected by LAPS: (Count: $Count)</b><br>"

#Add each computer found into body-variable
ForEach ($Computer in $Computers){

    $Body += "<br>" + $Computer.Name
}
#If no computers found, replace body
If ($Computers -eq $null){
    $Body = "No servers are missing LAPS - congratulation"
    Write-Host -ForegroundColor Yellow "No servers are missing LAPS"
}
#Sends the email
Send-MailMessage -To $To -From $From -Subject $Subject -Body $Body -smtpServer $SMTPServer -BodyAsHtml -Credential $AnonCredentials

Preview of the email being sent:

Bulk assigning O365 licenses, and then some… using Powershell

Managing our O365 licenses got me an idea to write one of my first Powershell scripts.

The script is tailored to our environment, but can be altered to fit any needs without much hassle. The script looks for users in specified OUs and compare them to what users in O365 that are assigned a license. All users in the specified OU are being assigned the specified license. If a license is assigned to a user, who does not exist in the specified OUs, the license is automatically removed. This way I’m always on top of who is using our licenses.

The script does the following for you in details:

  • (#2) Connects to O365 through Powershell (pre-req for that can be seen here: https://technet.microsoft.com/en-us/library/dn975125.aspx)
  • (#3) Reads what license you want to assign your users in the process. Change this to fit your needs and replace tenantname with your O365 tenant.
  • (#4) Reads what conditions you have for filtering what O365 users that needs a license. I’m excluding my Office 365 Admin and a few others, as I don’t wanna mess with the license for those users.
  • (#5) Reads the OUs containing user who needs a O365 license. You can specify several OUs if needed.
  • (#6) Assign the location and license for each user found in OUs. You can filter additionally in this step if needed.
  • (#7) Remove the O365 license, if user is not found in specified OUs. Change this to fit your needs and replace tenantname with your O365 tenant.
#_1_Imports relevant modules.
Import-Module ActiveDirectory
Import-Module MSOnline

#_2_Prompt for credentials used to log into O365.
$usercredentials = Get-Credential
Connect-MsolService -Credential $usercredentials

#_3_What license are we assigning the users.
$O365License = "tenantname:ENTERPRISEPACK"

#_4_Conditions for O365 users. Excluding certain accounts
$conditions = {$_.isLicensed -eq "TRUE" -AND $_.DisplayName -ne "Office 365 Admin" -AND $_.DisplayName -ne "Expectacademy" -AND $_.DisplayName -ne "London Printer"}

#_5_What OUs are we searching in.
$OUs = "CN=Schema,CN=Configuration,DC=EUROPE,DC=TEST,DC=CONTOSO,DC=COM","CN=Schema,CN=Configuration,DC=EUROPE,DC=TEST,DC=CONTOSO,DC=COM"

#_6_Search the OUs and return to variable. For each emailaddress found, assign to KR O365 license
$out = ForEach ($OU in $OUs) {get-aduser -SearchBase $OU -SearchScope 'Subtree' -Properties '*' -filter {(Description -ne 'Do not delete DMSForLegal') -AND (Enabled -eq $true)} | Select-Object UserPrincipalName}
$O365Users = Get-MsolUser -all | Where-Object $conditions | Select-Object UserPrincipalName
ForEach ($user in $out)
{
    $upn=$($user.UserPrincipalName)
    Set-MsolUser -UserPrincipalName $upn -UsageLocation DK
    Write-Host "Setting location to DK for $($user.UserPrincipalName)"

    Set-MsolUserLicense -UserPrincipalName $upn -AddLicenses $O365License -erroraction 'silentlycontinue'
    Write-Host "Assigning $($O365License) license for $($user.UserPrincipalName)"
}
#_7_For each user assigned to an O365 license, check if user exist in OUs. If not, remove the license. 
ForEach ($user in $O365Users)
{
    If (-Not($out -match $user))
    {
       Write-Host "Removing $($user.UserPrincipalName) from Office 365"
       Set-MsolUserLicense -UserPrincipalName $($user.UserPrincipalName) -RemoveLicenses "tenantname:ENTERPRISEPACK"
    }

}