Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@ markdownissues.txt
node_modules
package-lock.json
testfile.ps1
testfile1.ps1
ZZBuild-Help.ps1
exports/
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Added compliance policy management functions.

## [0.1.4] - 2024-07-30

### Added

- Added access token authentication
- Added User Managed Identity auth - Needs Testing
- Added System Manged Identity auth - Needs Testing
Expand Down
33 changes: 33 additions & 0 deletions source/Private/Get/Mdm/Get-EmMdmConditionalAccessPolicyAPI.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
function Get-EmMdmConditionalAccessPolicyAPI {
[cmdletBinding()]
param (
[Parameter(Mandatory = $false)]
[ValidateSet('beta', 'v1.0')]
[string]$graphApiVersion = 'beta',
[Parameter(Mandatory = $false)]
[string[]]$DisplayName
)
process {
$Resource = 'identity/conditionalAccess/policies'
$uriBase = "https://graph.microsoft.com/$graphApiVersion/$Resource"
try {
# Construct the URI with a filter query if DisplayName is provided
if ($DisplayName) {
$filterQuery = ($DisplayName | ForEach-Object { "displayName eq '$_'" }) -join ' or '
$uri = "$uriBase`?\$filter=$filterQuery"
}
else {
$uri = $uriBase
}
# Retrieve the data from Microsoft Graph API
$response = Invoke-MgGraphRequest -Uri $uri -Method GET
# Return the objects directly as they are already filtered server-side if DisplayName was provided
$objects = $response.value
Write-Verbose 'Conditional Access policies retrieved successfully.'
return $objects
}
catch {
throw "An error occurred while retrieving the Conditional Access policies: `n$_"
}
}
}
77 changes: 77 additions & 0 deletions source/Public/Backup/Backup-EmMdmConditionalAccessPolicy.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
function Backup-EmMdmConditionalAccessPolicy {
[cmdletBinding(
SupportsShouldProcess = $true,
ConfirmImpact = 'high'
)]
[OutputType([void])]
param (
[Parameter(
Mandatory = $true,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true,
HelpMessage = "The directory path where the Conditional Access policies will be exported."
)]
[ValidateNotNullOrEmpty()]
[String]$ExportPath,
[Parameter(
Mandatory = $false,
HelpMessage = "The authentication object used for connecting to Microsoft Graph."
)]
[EmMdmAuthBase]$AuthObject,
[Parameter(
DontShow = $true,
Mandatory = $false,
HelpMessage = "The version of the Microsoft Graph API to use. Valid values are 'beta' and 'v1.0'. The default value is 'beta'."
)]
[ValidateSet("beta", "v1.0")]
[string]$graphApiVersion = "beta"
)
begin {
try {
if ($PSCmdlet.ShouldProcess("Creating directory `"$(Split-Path -Path $ExportPath -Leaf)`" in `"$(Split-Path -Path $ExportPath -Parent)`" if not found.", "New-Item")) {
New-EmMdmBackupDirectory -ExportPath $ExportPath -Confirm:$false
}
if ($PSCmdlet.ShouldProcess("Connecting to MgGraph with scopes DeviceManagementConfiguration.Read.All", "Connect-MgGraph")) {
$isConnected = Connect-EmMdmGraph -Scopes "DeviceManagementConfiguration.Read.All" -AuthObject $AuthObject
}
}
catch {
throw $_
}
}
process {
try {
if ($isConnected -and $PSCmdlet.ShouldProcess("Getting Conditional Access policies and exporting to JSON", "Get-EmMdmAppConfigurationAPI")) {
$APPs = Get-EmMdmConditionalAccessPolicyAPI -graphApiVersion $graphApiVersion
if ($APPs.Length -eq 0) {
Write-Verbose "No policies found" -Verbose
throw "No policies found"
}
Write-Verbose "Exporting Conditional Access policies..." -Verbose
Backup-EmMdmPolicy -Policy $APPs -ExportPath $ExportPath -PolicyType "Conditional Access"
<#
foreach ($APP in $APPs) {
Write-Verbose "APP Protection Policy:"$APP.displayName -f Yellow
Export-JSONData -Policy $APP -ExportPath "$ExportPath" -AltName
Write-Verbose
}
#>
$ExportComplete = $true
}
}
catch {
throw "An error occurred while getting the Conditional Access policies: `n$_"
}
finally {
if ($isConnected) {
Write-Verbose "Disconnecting from MgGraph..." -Verbose
Disconnect-MgGraph | Out-Null
}
}
}
end {
if ($ExportComplete) {
Write-Verbose "Backup-EmMdmConditionalAccessPolicy completed." -Verbose
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
function Get-EmMdmConditionalAccessPolicy {
[cmdletBinding(
SupportsShouldProcess = $true,
ConfirmImpact = 'Medium'
)]
param (
[Parameter(
Mandatory = $false,
HelpMessage = "The authentication object used for connecting to Microsoft Graph."
)]
[EmMdmAuthBase]$AuthObject,
[Parameter(Mandatory = $false)]
[ValidateSet('beta', 'v1.0')]
[string]$graphApiVersion = 'beta',
[Parameter(Mandatory = $false)]
[string]$DisplayName
)
process {
try {
if ($PSCmdlet.ShouldProcess("Connecting to MgGraph with scopes Policy.Read.All", "Connect-MgGraph")) {
$isConnected = Connect-EmMdmGraph -Scopes "Policy.Read.All" -AuthObject $AuthObject
}

if ($PSCmdlet.ShouldProcess("Getting Conditional Access Policies", "Get-EmConditionalAccessPolicyAPI")) {
$CAPs = Get-EmMdmConditionalAccessPolicyAPI -graphApiVersion $graphApiVersion -DisplayName $DisplayName

if ($CAPs.Length -eq 0) {
Write-Verbose "No Conditional Access policies found" -Verbose
throw "No Conditional Access policies were found for the specified display name."
}

return $CAPs
}
}
catch {
throw "Get-EmConditionalAccessPolicy Error:`n $_"
}
finally {
if ($isConnected) {
Write-Verbose "Disconnecting from MgGraph..." -Verbose
Disconnect-MgGraph | Out-Null
}
}
}
}
92 changes: 92 additions & 0 deletions source/Public/Update-WinXPrimaryUser.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
function Update-WinXPrimaryUser {
<#
.SYNOPSIS
Removes and updates the primary user for specified devices in Microsoft Intune.
.DESCRIPTION
This function removes the primary user from specified devices and assigns the last logged-on user (retrieved via the Beta API) as the new primary user.
.PARAMETER DeviceNames
An array of device names for which the primary user will be updated.
.PARAMETER PreviewOnly
If specified, the function will display the proposed changes without making modifications.
.EXAMPLE
Update-WinXPrimaryUser -DeviceNames @('HostA', 'HostB') -PreviewOnly
.EXAMPLE
Update-WinXPrimaryUser -DeviceNames @('HostA', 'HostB') -Confirm
.NOTES
Author: Doug Rios
Date: March 4, 2025
#>
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')]
param (
[string[]]$DeviceNames,
[switch]$PreviewOnly
)
# Connect to Microsoft Graph with required scopes
Connect-MgGraph -Scopes "DeviceManagementManagedDevices.ReadWrite.All", "DeviceManagementConfiguration.ReadWrite.All"
foreach ($Device in $DeviceNames) {
# Retrieve the device information from Intune
$DeviceToModify = Get-MgDeviceManagementManagedDevice -Filter "DeviceName eq '$Device'" | Select-Object DeviceName, Id, userPrincipalName
if ($null -eq $DeviceToModify) {
Write-Output "No devices found with the name $Device"
continue
}
$DeviceId = $DeviceToModify.Id
$DeviceName = $DeviceToModify.DeviceName
$OldUser = $DeviceToModify.userPrincipalName
# Retrieve last logged-on user from Beta API
$BetaURI = "https://graph.microsoft.com/beta/deviceManagement/managedDevices('$DeviceId')"
try {
$LoggedOnUsers = (Invoke-MgGraphRequest -Method Get -Uri $BetaURI).usersLoggedOn
if ($null -eq $LoggedOnUsers) {
Write-Output "No recent user logins found for device $DeviceName"
continue
}
# Ensure it's an array and sort users by lastLogOnDateTime (descending)
$SortedUsers = $LoggedOnUsers | Sort-Object { $_.lastLogOnDateTime } -Descending
$MostRecentUser = $SortedUsers | Select-Object -First 1
if ($null -eq $MostRecentUser) {
Write-Output "No valid logon records found for device $DeviceName"
continue
}
$NewUserId = $MostRecentUser.userId
$LastLogonTime = $MostRecentUser.lastLogOnDateTime
Write-Output "Device: $DeviceName"
Write-Output " Current Primary User: $OldUser"
Write-Output " Proposed New User ID: $NewUserId (Last Logon: $LastLogonTime)"
# If PreviewOnly is set, just display the info
if ($PreviewOnly) {
continue
}
}
catch {
Write-Output "Failed to retrieve last logged-on user for device $DeviceName`: $($_.Exception.Message)"
continue
}
# Step 1: Remove the existing primary user
if ($PSCmdlet.ShouldProcess("Device $DeviceName", "Remove primary user ($OldUser)")) {
$RemoveURI = "https://graph.microsoft.com/v1.0/deviceManagement/managedDevices('$DeviceId')/users/`$ref"
try {
Invoke-MgGraphRequest -Method DELETE -Uri $RemoveURI
Write-Output "Primary user ($OldUser) removed from device $DeviceName"
}
catch {
Write-Output "Failed to remove primary user from device $DeviceName`: $($_.Exception.Message)"
continue
}
}
# Step 2: Assign the new user as the primary user
if ($PSCmdlet.ShouldProcess("Device $DeviceName", "Assign primary user ($NewUserId)")) {
$AssignURI = "https://graph.microsoft.com/v1.0/deviceManagement/managedDevices('$DeviceId')/users/`$ref"
$Body = @{
"@odata.id" = "https://graph.microsoft.com/v1.0/users/$NewUserId"
} | ConvertTo-Json -Depth 1
try {
Invoke-MgGraphRequest -Method POST -Uri $AssignURI -Body $Body -ContentType "application/json"
Write-Output "Primary user ($NewUserId) assigned to device $DeviceName"
}
catch {
Write-Output "Failed to assign new primary user to device $DeviceName`: $($_.Exception.Message)"
}
}
}
}