Private/Collectors.LocalAccounts.ps1
|
function Get-ICLocalAccountEvidence { [CmdletBinding()] param( [Parameter(Mandatory)] [object]$Context ) $warnings = New-Object System.Collections.ArrayList $files = New-Object System.Collections.ArrayList $users = @() $groups = @() $members = @() if (Test-ICCommandAvailable -Name 'Get-LocalUser') { try { $users = @(Get-LocalUser -ErrorAction Stop | ForEach-Object { [pscustomobject][ordered]@{ Name = $_.Name SID = [string]$_.SID Enabled = $_.Enabled Description = $_.Description FullName = $_.FullName AccountExpiresUtc = ConvertTo-ICIso8601 -Value $_.AccountExpires PasswordLastSetUtc = ConvertTo-ICIso8601 -Value $_.PasswordLastSet PasswordExpiresUtc = ConvertTo-ICIso8601 -Value $_.PasswordExpires UserMayChangePassword = $_.UserMayChangePassword PasswordRequired = $_.PasswordRequired LastLogonUtc = ConvertTo-ICIso8601 -Value $_.LastLogon PrincipalSource = [string]$_.PrincipalSource } } | Sort-Object Name) } catch { Add-ICCollectorWarning -List $warnings -Message "Local users: $($_.Exception.Message)" } try { $groups = @(Get-LocalGroup -ErrorAction Stop | ForEach-Object { [pscustomobject][ordered]@{ Name = $_.Name SID = [string]$_.SID Description = $_.Description PrincipalSource = [string]$_.PrincipalSource } } | Sort-Object Name) } catch { Add-ICCollectorWarning -List $warnings -Message "Local groups: $($_.Exception.Message)" } foreach ($group in $groups) { try { $groupMembers = @(Get-LocalGroupMember -Group $group.Name -ErrorAction Stop | ForEach-Object { [pscustomobject][ordered]@{ Group = $group.Name GroupSID = $group.SID Name = $_.Name SID = [string]$_.SID ObjectClass = $_.ObjectClass PrincipalSource = [string]$_.PrincipalSource } }) $members += $groupMembers } catch { Add-ICCollectorWarning -List $warnings -Message "Local group '$($group.Name)' membership: $($_.Exception.Message)" } } } else { Add-ICCollectorWarning -List $warnings -Message 'Microsoft.PowerShell.LocalAccounts cmdlets are unavailable; CIM fallback provides basic inventory without reliable memberships.' try { $users = @(Get-CimInstance -ClassName Win32_UserAccount -Filter 'LocalAccount=True' -ErrorAction Stop | ForEach-Object { [pscustomobject][ordered]@{ Name = $_.Name SID = $_.SID Disabled = $_.Disabled Lockout = $_.Lockout Description = $_.Description FullName = $_.FullName PasswordChangeable = $_.PasswordChangeable PasswordExpires = $_.PasswordExpires PasswordRequired = $_.PasswordRequired Status = $_.Status } }) } catch { Add-ICCollectorWarning -List $warnings -Message "CIM local users: $($_.Exception.Message)" } try { $groups = @(Get-CimInstance -ClassName Win32_Group -Filter 'LocalAccount=True' -ErrorAction Stop | ForEach-Object { [pscustomobject][ordered]@{ Name = $_.Name SID = $_.SID Description = $_.Description Status = $_.Status } }) } catch { Add-ICCollectorWarning -List $warnings -Message "CIM local groups: $($_.Exception.Message)" } } Add-ICOutputFiles -List $files -Path (Export-ICCollectorData -Context $Context -Collector LocalAccounts -RelativePath 'evidence/identities/local-users.json' -Data $users -Csv) Add-ICOutputFiles -List $files -Path (Export-ICCollectorData -Context $Context -Collector LocalAccounts -RelativePath 'evidence/identities/local-groups.json' -Data $groups -Csv) Add-ICOutputFiles -List $files -Path (Export-ICCollectorData -Context $Context -Collector LocalAccounts -RelativePath 'evidence/identities/local-group-members.json' -Data $members -Csv) return New-ICCollectorResultData -OutputFiles @($files) -Warnings @($warnings) -Metrics ([ordered]@{ LocalUsers = $users.Count EnabledLocalUsers = @($users | Where-Object { (Get-ICPropertyValue -InputObject $_ -Name 'Enabled' -Default (-not (Get-ICPropertyValue -InputObject $_ -Name 'Disabled' -Default $false))) -eq $true }).Count LocalGroups = $groups.Count GroupMembershipRows = $members.Count }) } |