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
5 changes: 0 additions & 5 deletions .github/linters/.textlintrc
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,6 @@
"ZIP",
"McKenzie",
"McConnell",
"ID",
[
"id['’]?s",
"IDs"
],
[
"backwards compatible",
"backward compatible"
Expand Down
79 changes: 72 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,19 @@ Here is a list of example that are typical use cases for the module.

### Example 1: Get-IntuneDeviceLogin

As for March 2026 there is one cmdlet: `Get-IntuneDeviceLogin`.
As of March 2026, the module has three cmdlets: `Get-IntuneDeviceLogin`, `Get-IntuneRemediationSummary` and `Get-IntuneRemediationDeviceStatus`.

```powershell
Get-IntuneDeviceLogin -DeviceName PC-001
```

```text
DeviceName : PC-001
OperatingSystem : Windows
UserPrincipalName : john.doe@contoso.com
DeviceId : c1f5d1d7-2d2b-4d8c-9f0a-0d2a3d1e2f3a
UserId : a5b6c7d8-e9f0-1a2b-3c4d-5e6f7a8b9c0d
LastLogonDateTime : 3/9/2026 8:14:00 AM

DeviceName : PC-001
UserPrincipalName : jane.smith@contoso.com
DeviceId : c1f5d1d7-2d2b-4d8c-9f0a-0d2a3d1e2f3a
UserId : b1c2d3e4-f5a6-7b8c-9d0e-1f2a3b4c5d6e
LastLogonDateTime : 3/7/2026 2:45:00 PM
```

```powershell
Expand All @@ -50,18 +45,88 @@ Get-IntuneDeviceLogin -UserPrincipalName john.doe@contoso.com

```text
DeviceName : PC-001
OperatingSystem : Windows
UserPrincipalName : john.doe@contoso.com
DeviceId : c1f5d1d7-2d2b-4d8c-9f0a-0d2a3d1e2f3a
UserId : a5b6c7d8-e9f0-1a2b-3c4d-5e6f7a8b9c0d
LastLogonDateTime : 3/9/2026 8:14:00 AM

DeviceName : PC-042
OperatingSystem : Windows
UserPrincipalName : john.doe@contoso.com
DeviceId : f7e6d5c4-b3a2-1f0e-9d8c-7b6a5f4e3d2c
UserId : a5b6c7d8-e9f0-1a2b-3c4d-5e6f7a8b9c0d
LastLogonDateTime : 3/5/2026 9:33:00 AM
```

### Example 2: Get-IntuneRemediationSummary

```powershell
Get-IntuneRemediationSummary
```

```text
Name : Fix BitLocker
Status : Completed
WithoutIssues : 214
WithIssues : 3
IssueFixed : 47
IssueRecurred : 1
TotalRemediated : 47

Name : Disable NetBIOS
Status : Completed
WithoutIssues : 217
WithIssues : 0
IssueFixed : 0
IssueRecurred : 0
TotalRemediated : 0
```

### Example 3: Get-IntuneRemediationDeviceStatus

```powershell
Get-IntuneRemediationDeviceStatus -Name 'BitLocker detection and remediation'
```

```text
RemediationName : BitLocker detection and remediation
RemediationId : b2bf3efa-b16d-4936-866c-560592e4d35a
DeviceId : c1f5d1d7-2d2b-4d8c-9f0a-0d2a3d1e2f3a
DeviceName : PC-001
UserPrincipalName : john.doe@contoso.com
LastStateUpdate : 3/11/2026 6:00:00 AM
DetectionState : success
RemediationState : success
PreRemediationOutput : BitLocker status: Off
PostRemediationOutput : BitLocker status: On
DetectionOutput :
PreRemediationError :
RemediationError :
DetectionError :

RemediationName : BitLocker detection and remediation
RemediationId : b2bf3efa-b16d-4936-866c-560592e4d35a
DeviceId : f7e6d5c4-b3a2-1f0e-9d8c-7b6a5f4e3d2c
DeviceName : PC-042
UserPrincipalName : jane.smith@contoso.com
LastStateUpdate : 3/11/2026 6:05:00 AM
DetectionState : fail
RemediationState : remediationFailed
PreRemediationOutput : BitLocker status: Off
PostRemediationOutput : BitLocker status: Off
DetectionOutput :
PreRemediationError :
RemediationError : Exit code: 1 - Access denied
DetectionError :
```

You can also pipe from `Get-IntuneRemediationSummary` to only inspect remediations that have devices with issues:

```powershell
Get-IntuneRemediationSummary | Where-Object WithIssues -gt 0 | Get-IntuneRemediationDeviceStatus
```

## Acknowledgements

- [Process-Module](https://github.com/PSModule/Process-PSModule) by [Marius Storhaug](https://github.com/MariusStorhaug). Contains the entire build pipeline. This is greatly beneficial and helps me just concentrating on building the cmdlets.
85 changes: 85 additions & 0 deletions src/functions/private/Get-FirstPropertyValue.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
function Get-FirstPropertyValue {
<#
.SYNOPSIS
Returns the first non-empty property value from an object or dictionary.

.DESCRIPTION
Checks each property name in order against the input object, dictionary keys,
and an AdditionalProperties dictionary when present. Returns the first value
that is not null and not empty/whitespace when converted to string.

.PARAMETER InputObject
The object or dictionary to inspect.

.PARAMETER PropertyNames
The ordered list of property names to evaluate.

.PARAMETER DefaultValue
The value to return when none of the requested properties contain a value.

.EXAMPLE
Get-FirstPropertyValue -InputObject $Object -PropertyNames @('displayName', 'name')

Returns the first populated value found in `displayName` or `name`.

.INPUTS
System.Object

.OUTPUTS
System.Object
#>

[OutputType([object])]
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[AllowNull()]
[object]$InputObject,

[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[string[]]$PropertyNames,

[Parameter(Mandatory = $false)]
[AllowNull()]
[object]$DefaultValue = $null
)

process {
if ($null -eq $InputObject) {
return $DefaultValue
}

$additionalProperties = $InputObject.PSObject.Properties['AdditionalProperties']
$additionalPropertiesValue = $null
if ($null -ne $additionalProperties -and $additionalProperties.Value -is [System.Collections.IDictionary]) {
$additionalPropertiesValue = $additionalProperties.Value
}

foreach ($propertyName in $PropertyNames) {
if ($InputObject -is [System.Collections.IDictionary] -and $InputObject.Contains($propertyName)) {
$dictionaryValue = $InputObject[$propertyName]
if ($null -ne $dictionaryValue -and -not [string]::IsNullOrWhiteSpace([string]$dictionaryValue)) {
return $dictionaryValue
}
}

$property = $InputObject.PSObject.Properties[$propertyName]
if ($null -ne $property) {
$value = $property.Value
if ($null -ne $value -and -not [string]::IsNullOrWhiteSpace([string]$value)) {
return $value
}
}

if ($null -ne $additionalPropertiesValue -and $additionalPropertiesValue.Contains($propertyName)) {
$apValue = $additionalPropertiesValue[$propertyName]
if ($null -ne $apValue -and -not [string]::IsNullOrWhiteSpace([string]$apValue)) {
return $apValue
}
}
}

return $DefaultValue
}
}
Loading
Loading