Category Archives: Powershell

Lightweight LAPS solution for INtune (MEM)

Managing local admin accounts using Intune has a lot of quirks, my tele-colleague Rudy Ooms has already written extensively about this. He also wrote a PowerShell solution to rotate a specific local admin’s password and had the genius idea of using Proactive Remediations (a MEM feature) to display passwords to admins, integrated / free in the Intune Console.

However, I felt I needed a more lightweight solution that;

  • does not require/modify registry keys
  • does not store the password locally
  • does not need separate detection and remediation scripts
  • automatically provisions a local admin account
  • can remove any other local admin accounts if desired
  • is language/locale-agnostic (e.g. ‘Administrators’ vs ‘Administradores’….)

Thus LeanLAPS was born!

To install/use:

1. head into the Proactive Remediations section of MDE and click Create script package:

2. Fill out some details:

3. Download and doublecheck the config of LeanLAPS.ps1 (e.g. configure if other local admins should be removed, what the local admin name should be and the password length). Make sure to use NotePad++ / that the file stays UTF-8 Encoded without a BOM.

4. Set both the detection and remediation script to LeanLAPS.ps1 and run it in 64 bit:

5. Assign to a device group (user groups won’t work) and deploy. By default it will run every day, but you can also let it run more or less frequently, which determines how often the password is reset (hourly in below example):

6. Deploy, and then click on the script package:

7. Go to Device status and add both output columns:

Congratulations, you can now see the current local admin passwords for all managed Windows 10 devices!

Note: if you wish to trigger a quick remediation, delete the correct keys under Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\IntuneManagementExtension\SideCarPolicies\Scripts\Execution and Reports in the client’s registry, then restart the IntuneManagementExtension service and the remediation will re-run within 5 minutes.

RBAC

If you provide e.g. your helpdesk with the correct Intune roles, they will be able to see local admin passwords as reported by above solution:

Previewing image.png

Configuring the Windows 10 Pro Lock Screen using MEM

Windows 10 Enterprise supports a specific MEM policy to configure the Windows 10 Lock screen for End-users. If you’re unlucky enough to be on a lesser Windows 10 version, you’ll need to trick the OS into thinking the lock screen is modified by the user instead of through a policy.

Here’s a simple ARM template for blob storage and a PS script to deploy through MEM in user context to configure the lock screen of your users:

1-click ARM template

And the script itself (don’t forget to configure the image URL):

<#
    .SYNOPSIS
    Sets custom lock screen based on file in an Azure Storage Blob container
    See blob template to automatically configure a blob container: https://gitlab.com/Lieben/assortedFunctions/-/blob/master/ARM%20templates/blob%20storage%20with%20container%20for%20Teams%20Backgrounds%20and%20public%20access.json
   
    .NOTES
    filename: set-windows10LockScreen.ps1
    author: Jos Lieben
    blog: www.lieben.nu
    created: 13/05/2021
#>

$changedDate = "2021-05-13"
$lockscreenFileURL = "https://tasdsadgsadsad.blob.core.windows.net/teamsbackgrounds/figure-a.jpg" #this is the full URL to the desired lock screen image

Start-Transcript -Path (Join-Path -Path $Env:TEMP -ChildPath "set-windows10LockScreen.log")

$tempFile = (Join-Path $Env:TEMP -ChildPath "img100.jpg")

try{
    Write-Output "downloading lock screen file from $lockscreenFileURL"
    Invoke-WebRequest -Uri $lockscreenFileURL -UseBasicParsing -Method GET -OutFile $tempFile
    Write-Output "file downloaded to $tempFile"
}catch{
    Write-Output "Failed to download file, aborting"
    Write-Error $_ -ErrorAction SilentlyContinue
    Exit
}

[Windows.System.UserProfile.LockScreen,Windows.System.UserProfile,ContentType=WindowsRuntime] | Out-Null
Add-Type -AssemblyName System.Runtime.WindowsRuntime

$asTaskGeneric = ([System.WindowsRuntimeSystemExtensions].GetMethods() | ? { $_.Name -eq 'AsTask' -and $_.GetParameters().Count -eq 1 -and $_.GetParameters()[0].ParameterType.Name -eq 'IAsyncOperation`1' })[0]
Function Await($WinRtTask, $ResultType) {
    $asTask = $asTaskGeneric.MakeGenericMethod($ResultType)
    $netTask = $asTask.Invoke($null, @($WinRtTask))
    $netTask.Wait(-1) | Out-Null
    $netTask.Result
}

Function AwaitAction($WinRtAction) {
    $asTask = ([System.WindowsRuntimeSystemExtensions].GetMethods() | ? { $_.Name -eq 'AsTask' -and $_.GetParameters().Count -eq 1 -and !$_.IsGenericMethod })[0]
    $netTask = $asTask.Invoke($null, @($WinRtAction))
    $netTask.Wait(-1) | Out-Null
}

[Windows.Storage.StorageFile,Windows.Storage,ContentType=WindowsRuntime] | Out-Null
		
try{
	$image = Await ([Windows.Storage.StorageFile]::GetFileFromPathAsync($tempFile)) ([Windows.Storage.StorageFile])
    Write-Output "Image loaded from $tempFile"
}catch {
    Write-Output "Failed to load image from $tempFile"
    Write-Error $_ -ErrorAction SilentlyContinue
    Exit
} 
       
try{ 
    Write-Output "Setting image as lock screen image"
    AwaitAction ([Windows.System.UserProfile.LockScreen]::SetImageFileAsync($image))
    Write-Output "$tempFile configured as lock screen image"
    Remove-Item -Path $tempFile -Force -Confirm:$False
}catch{
    Write-Output "Failed to set lock screen image"
    Write-Error $_ -ErrorAction SilentlyContinue
} 

Write-Output "Script complete"
Stop-Transcript

Source: https://gitlab.com/Lieben/assortedFunctions/-/blob/master/set-windows10LockScreen.ps1

Deploying in user context:

Copying filesystem permissions for long paths using AlphaFS nad Powershell

AlphaFS is my go-to library when working with Long Paths, since PowerShell’s built in functions do not support long paths and error out.

As I couldn’t find good PowerShell examples using GetAccessControl and SetAccessControl with the AlphaFS library, I wanted to post my script here for those googling an example 🙂

Param(
    [String]$sourcePath,
    [String]$targetPath
)

[System.Reflection.Assembly]::UnsafeLoadFrom('https://gitlab.com/Lieben/assortedFunctions/-/raw/master/lib/AlphaFS.dll?inline=false')

$sourcePath = [Alphaleonis.Win32.Filesystem.Path]::GetLongPath($sourcePath)
$targetPath = [Alphaleonis.Win32.Filesystem.Path]::GetLongPath($targetPath)

if([Alphaleonis.Win32.Filesystem.Directory]::Exists($sourcePath)){
    Write-Verbose "Detected sourcePath as FOLDER"
    $sourceObject = New-Object Alphaleonis.Win32.Filesystem.DirectoryInfo($sourcePath)
}elseif([Alphaleonis.Win32.Filesystem.File]::Exists($sourcePath)){
    Write-Verbose "Detected sourcePath as FILE"
    $sourceObject = New-Object Alphaleonis.Win32.Filesystem.FileInfo($sourcePath)
}else{
    Throw "sourcePath not found"
}

if([Alphaleonis.Win32.Filesystem.Directory]::Exists($targetPath)){
    Write-Verbose "Detected targetPath as FOLDER"   
    $targetObject = New-Object Alphaleonis.Win32.Filesystem.DirectoryInfo($targetPath)
}elseif([Alphaleonis.Win32.Filesystem.File]::Exists($targetPath)){
    Write-Verbose "Detected targetPath as FILE"
    $targetObject = New-Object Alphaleonis.Win32.Filesystem.FileInfo($targetPath)
}else{
    Throw "targetPath not found"
}

$sourceACL = $sourceObject.GetAccessControl("Access")
$targetObject.SetAccessControl($sourceACL)

Git: https://gitlab.com/Lieben/assortedFunctions/-/blob/master/copy-longPathACL.ps1

Distributing Teams Backgrounds to all users using MEM

I’ve seen a few examples of distributing a set of teams backgrounds to users in MEM, mostly they seemed a little overly complex, especially in targetting all local users and/or packaging the script into an application. I wanted to:

  • Deploy using MEM PS script in user context
  • Avoid access controls on the storage location of the backgrounds
  • Simplify the creation of required Azure resources
  • Have a simple update procedure

Here’s my take, first autocreate a blob storage location using my template:

https://gitlab.com/Lieben/assortedFunctions/-/blob/master/ARM%20templates/blob%20storage%20with%20container%20for%20Teams%20Backgrounds%20and%20public%20access.json

Note down the name you used for the storage account (which was the only parameter to the template), and use it to configure this PowerShell script:

https://gitlab.com/Lieben/assortedFunctions/-/blob/master/add-teamsBackgroundsFromBlobContainer.ps1

Finally, deploy the script to a group of your users in MEM, in their own context: