UsersToDevices.psm1


function Add-User-Devices
{

<#
.SYNOPSIS
 
Finds registered devices of users in UserGroup and adds them into DeviceGroup.
 
.DESCRIPTION
 
Author: David Velasquez
Dependencies:
AzureAD Module
NuGet provider version '2.8.5.201' or newer
 
Optional Dependency:
ImportExcel Module
 
Accepts [-Excel] as optional parameter to generate an excel spreadsheet report.
 
Accepts [-Mobile] as optional parameter to only add mobile devices to [-DeviceGroup].
 
Accepts [-E] and [-M] as parameter aliases for [-Excel] and [-Mobile].
 
Accepts [-From] and [-To] as parameter aliases for [-UserGroup] and [-DeviceGroup].
 
Example:
 
Add-User-Devices [-From] <String> [-To] <String> [-E] [-M] [<CommonParameters>]
 
Note: <string> is the ObjectID of the User and Device groups.
 
.PARAMETER UserGroup
 
Specifies the name of the user group where users can be found.
 
.PARAMETER DeviceGroup
 
Specifies the name of the device group where registered devices should be placed.
 
.PARAMETER Excel
 
Optional: Generates an excel spreadsheet report and will open in excel if installed.
 
.PARAMETER Mobile
 
Optional: Specifies the name of the device group where registered mobile devices should be placed.
 
.EXAMPLE
 
PS C:\> Add-User-Devices -UserGroup <ObjectID> -DeviceGroup <ObjectID>
 
.EXAMPLE
 
PS C:\> Add-User-Devices -From <ObjectID> -To <ObjectID>
 
.EXAMPLE
 
PS C:\> Add-User-Devices -From <ObjectID> -To <ObjectID> -Excel
 
.EXAMPLE
 
PS C:\> Add-User-Devices -From <ObjectID> -To <ObjectID> -Mobile
 
.EXAMPLE
 
PS C:\> Add-User-Devices -From <ObjectID> -To <ObjectID> -E -M
 
.LINK
 
https://www.powershellgallery.com/packages/UsersToDevices
 
#>


[CmdletBinding()] Param(
        [Parameter(Mandatory = $True,HelpMessage='User Group ObjectId')]
        [Alias("From")]
        [String]
        $UserGroup,

        [Parameter(Mandatory = $True,HelpMessage='Device Group ObjectId')]
        [Alias("To")]
        [String]
        $DeviceGroup,
        
        [Parameter(Mandatory = $False)]
        [Alias("M")]
        [switch]
        $Mobile,
        
        [Parameter(Mandatory = $False)]
        [Alias("E")]
        [switch]
        $Excel
)
    if (!(Connected)) {Azure-Ad-Auth}
    #Write-Host "`nFinding registered devices"
    $UserList = Get-AzureADGroupMember -ObjectId $UserGroup -All $true | Sort-Object -Property DisplayName
    If (!($UserList)) { Write-Host "No users were found - exiting" ; break }
    Write-Host ("`nProcessing details for {0} users" -f $UserList.count) -ForegroundColor Green

    $DeviceList = Get-AzureADGroupMember -ObjectId $DeviceGroup -All $true | Sort-Object -Property DisplayName
    $global:UserGroupName = (Get-AzureADGroup -objectid $UserGroup).displayname
    $global:DeviceGroupName = (Get-AzureADGroup -objectid $DeviceGroup).displayname

    $i = 0
    foreach ($User in $UserList)
    {
    $i++
    Write-Host ("`nFinding devices registered to {0} ({1}/{2})" -f $User.DisplayName, $i, $UserList.count) -ForegroundColor Yellow
    $DeviceQuery = Get-AzureADUserRegisteredDevice -objectid $User.objectid -All $true
    if ($Mobile)
    {
        $Devices = $DeviceQuery | where-object { ($_.displayname -like "*iphone*") -or ($_.displayname -like "*ipad*") }
    }
    else
    {
        $Devices = $DeviceQuery | where-object { ($_.displayname -notlike "*iphone*") -and ($_.displayname -notlike "*MacBook*") -and ($_.displayname -notlike "*ipad*") -and ($_.displayname -notlike "*vdi*") -and ($_.displayname -notlike "*yealink*") -and ($_.displayname -notlike "*android*") }
    }
        $j = 0
        foreach ($Device in $Devices)
        {
            $j++
            if ($Device -ne $null)
            {
                if ($DeviceList.objectid -notcontains  $Device.objectid)
                {
                    Write-Host ("`nProcessing ({0}/{1}) devices for {2}" -f $j, $Devices.count, $User.DisplayName) -ForegroundColor Green
                    Write-Host ("`nAdding {0}'s {1} to {2}" -f $User.DisplayName, $Device.displayname, $DeviceGroupName) -ForegroundColor Cyan
                    Add-AzureADGroupMember -ObjectId $DeviceGroup -RefObjectId $Device.objectid
                }
                else
                {
                    Write-Host ("`nProcessing ({0}/{1}) devices for {2}" -f $j, $Devices.count, $User.DisplayName) -ForegroundColor Green
                    Write-Host ("`n{0}'s {1} is already a member of {2}" -f $User.DisplayName, $Device.displayname, $DeviceGroupName) -ForegroundColor Red
                }
            }
        }
    }
    
    write-host ""
    Write-Host -ForegroundColor Yellow -NoNewLine 'Press any key to continue and generate report... ';
    $null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');

    if ($Excel)
    {
        Get-Report -From $UserGroup -To $DeviceGroup -Excel
    }
    else
    {
        Get-Report -From $UserGroup -To $DeviceGroup
    }
}

function Connected()
{
    $retval = $true
    try { 
     $Status = Get-AzureADTenantDetail 
    } 
    catch [Microsoft.Open.Azure.AD.CommonLibrary.AadNeedAuthenticationException] {
     $retval = $false
     return $retval
    }
    return $retval
}

function Azure-Ad-Auth()
{

    $NuGet = (Get-packageprovider -ListAvailable -Name NuGet -ea silentlycontinue)
    if (!$NuGet)
    {
        Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force | Out-Null
    }
    Import-PackageProvider -Name NuGet | Out-Null
    $AzureAD = (Get-Module -ListAvailable -Name AzureAD -ea silentlycontinue)
    if (!$AzureAD)
    {
        Install-Module -Name AzureAD -Force | Out-Null
    }
    Import-Module AzureAD | Out-Null
    $mod = get-module AzureAD
    if ($mod -ne $null)
    {
        try
        {
            clear
            Connect-AzureAD
            clear
        }
        catch
        {
            clear
            write-host
            Write-warning "Could not connect to Azure AD"
            write-host
            exit
        }
    }
}


function Get-Report()
{

<#
.SYNOPSIS
 
Generates report based on registered devices of users in UserGroup and devices in DeviceGroup.
 
.DESCRIPTION
 
Author: David Velasquez
Dependencies:
AzureAD Module
NuGet provider version '2.8.5.201' or newer
 
Optional Dependency:
ImportExcel Module
 
Accepts [-Excel] as optional parameter to generate an excel spreadsheet report.
 
Accepts [-E] as parameter alias for [-Excel].
 
Accepts [-From] and [-To] as parameter aliases for [-UserGroup] and [-DeviceGroup].
 
Example:
 
Get-Report [-From] <String> [-To] <String> [-E] [<CommonParameters>]
 
Note: <string> is the ObjectID of the User and Device groups.
 
.PARAMETER UserGroup
 
Specifies the name of the user group where users can be found.
 
.PARAMETER DeviceGroup
 
Specifies the name of the device group where registered devices should be located.
 
.PARAMETER Excel
 
Optional: Generates an excel spreadsheet report and will open in excel if installed.
 
.EXAMPLE
 
PS C:\> Get-Report -UserGroup <ObjectID> -DeviceGroup <ObjectID>
 
.EXAMPLE
 
PS C:\> Get-Report -From <ObjectID> -To <ObjectID>
 
.EXAMPLE
 
PS C:\> Get-Report -From <ObjectID> -To <ObjectID> -Excel
 
.EXAMPLE
 
PS C:\> Get-Report -From <ObjectID> -To <ObjectID> -E
 
.LINK
 
https://www.powershellgallery.com/packages/UsersToDevices
 
#>


[CmdletBinding()] Param(
        [Parameter(Mandatory = $True,HelpMessage='User Group ObjectId')]
        [Alias("From")]
        [String]
        $UserGroup,

        [Parameter(Mandatory = $True,HelpMessage='Device Group ObjectId')]
        [Alias("To")]
        [String]
        $DeviceGroup,
        
        [Parameter(Mandatory = $False)]
        [Alias("E")]
        [switch]
        $Excel
)

    if (!(Connected)) {Azure-Ad-Auth}
    $UserList = Get-AzureADGroupMember -ObjectId $UserGroup -All $true | Sort-Object -Property DisplayName
    $DeviceList = Get-AzureADGroupMember -ObjectId $DeviceGroup -All $true | Sort-Object -Property DisplayName
    $global:UserGroupName = (Get-AzureADGroup -objectid $UserGroup).displayname
    $global:DeviceGroupName = (Get-AzureADGroup -objectid $DeviceGroup).displayname
    $global:Report = [System.Collections.Generic.List[Object]]::new() 

    foreach ($User in $UserList)
    {
    $DeviceQuery = Get-AzureADUserRegisteredDevice -objectid $User.objectid -All $true
    $Devices = $DeviceQuery | where-object { ($_.displayname -notlike "*iphone*") -and ($_.displayname -notlike "*ipad*") -and ($_.displayname -notlike "*MacBook*") -and ($_.displayname -notlike "*vdi*") -and ($_.displayname -notlike "*android*") -and ($_.displayname -notlike "*yealink*") }
    $iPhones = $DeviceQuery | where-object {$_.displayname -like "*iphone*"}
    $iPads = $DeviceQuery | where-object {$_.displayname -like "*ipad*"}
    $Laptops = $DeviceQuery | where-object {$_.displayname -like "*-LT-*"}
    $AppleLaptops = $DeviceQuery | where-object {$_.displayname -like "*MacBook*"}
    $Desktops = $DeviceQuery | where-object { ($_.displayname -notlike "*iphone*") -and ($_.displayname -notlike "*ipad*") -and ($_.displayname -notlike "*MacBook*") -and ($_.displayname -notlike "*vdi*") -and ($_.displayname -notlike "*-LT-*") -and ($_.displayname -notlike "*android*") -and ($_.displayname -notlike "*yealink*") }
    $MobileDevices = $DeviceQuery | where-object { ($_.displayname -like "*iphone*") -or ($_.displayname -like "*ipad*") }
    $VirtualDesktops = $DeviceQuery | where-object {$_.displayname -like "*VDI-*"}
    $DevicesInDeviceGroup = $DeviceQuery | where-object { ($_.objectid -in $DeviceList.objectid) -and ($_.displayname -notlike "*iphone*") -and ($_.displayname -notlike "*ipad*") -and ($_.displayname -notlike "*MacBook*") -and ($_.displayname -notlike "*vdi*") -and ($_.displayname -notlike "*android*") }
    $MobileDevicesInDeviceGroup = $DeviceQuery | where-object { ($_.objectid -in $DeviceList.objectid) -and ($_.displayname -like "*iphone*") -or ($_.displayname -like "*ipad*") }

    $Lines = [PSCustomObject]@{
    User = $User.displayname
    UserObjectID = $User.objectid
    UserGroup = $UserGroupName
    UserGroupObjectID = $UserGroup
    DeviceGroup = $DeviceGroupName
    DeviceGroupObjectID = $DeviceGroup
    Devices = $Devices.displayname
    DeviceObjectIDs = $Devices.objectid
    DesktopDevices = $Desktops.displayname
    DesktopDeviceIDs = $Desktops.objectid
    LaptopDevices = $Laptops.displayname
    LaptopDeviceIDs = $Laptops.objectid
    AppleLaptopDevices = $AppleLaptops.displayname
    AppleLaptopDeviceIDs = $AppleLaptops.objectid
    iPadDevices = $iPads.displayname
    iPadDeviceIDs = $iPads.objectid
    iPhoneDevices = $iPhones.displayname
    iPhoneDeviceIDs = $iPhones.objectid
    VirtualDesktopDevices = $VirtualDesktops.displayname
    VirtualDesktopDeviceIDs = $VirtualDesktops.objectid
    CustomAttributes = $null
    DevicesInDeviceGroup = $DevicesInDeviceGroup.displayname
    DevicesInDeviceGroupIDs = $DevicesInDeviceGroup.objectid
    MobileDevicesInDeviceGroup = $MobileDevicesInDeviceGroup.displayname
    MobileDevicesInDeviceGroupIDs = $MobileDevicesInDeviceGroup.objectid
    }
    $Report.Add($Lines)

    }
    clear
    Write-Host "`nGenerated Report"
    Write-Host "----------------`n"
    $Report
    $Report | Pretty-Table | Out-GridView -wait

    $ExcelParam = $null
    if ($Excel)
    {
        if ((Enum-Excel-Module))
        {
            $ExcelParam = "-Excel"
            Output-To-Excel
        }
    }
    
    write-host "`nReport Generated by running:" -ForegroundColor Magenta
    write-host ("Get-Report -From {0} -To {1} {2}" -f $UserGroup, $DeviceGroup, $ExcelParam) -ForegroundColor Magenta
}

function Output-To-Excel()
{
    
    
$xlfile = "$env:USERPROFILE\Desktop\PSreport.xlsx"
Remove-Item $xlfile -ErrorAction SilentlyContinue

$excel = $Report | Pretty-Table | Export-Excel $xlfile -AutoSize -StartRow 2 -TableName GeneratedReport -PassThru

$ws = $excel.Workbook.Worksheets['Sheet1']

$xlParams = @{WorkSheet=$ws;Bold=$true;FontSize=24;AutoSize=$true}

Set-Format -Range A1  -Value "Generated Report" @xlParams

$ws.Cells["A1:B1"].merge = $true

$ws.Cells["A:B"].Style.HorizontalAlignment="Center"

Set-ExcelRange -Worksheet $ws -Range "A:B" -Width 50

#Set-ExcelRange -Worksheet $ws -Range "A3:B3" -Bold

$rowMax = ($ws).dimension.rows
$colNameA = "A"
$columnB = "B"
for ($i=3; $i -le $rowMax-1; $i = $i + 25)
{
    $range =  -join($colNameA, $i, ":", $columnB, $i)
    Set-ExcelRange -Worksheet $ws -Range "$range" -Bold -FontSize "20"
}

write-host ("Generated Report Saved to: {0}" -f $xlfile) -ForegroundColor Magenta

$HasOffice = (Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\O365ProPlusRetail*).displayname

if ($HasOffice)
{
    Close-ExcelPackage $excel -show
}
else
{
Close-ExcelPackage $excel
}

}

function Pretty-Table()
{
    param
    (
        [Object]
        [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
        $InputObject
    )
    process
    {
        
        $InputObject |
        ForEach-Object {
        foreach ($Property in $_.psobject.properties)
            {
                $Hash = [ordered]@{
                    Property=$Property.name
                    Value=$Property.value
                }
            [PSCustomObject]$Hash
            }
        }
    }
}

function Enum-Excel-Module()
{
    Import-PackageProvider -Name NuGet | Out-Null
    $ImportExcel = (Get-Module -ListAvailable -Name ImportExcel -ea silentlycontinue)
    if (!$ImportExcel)
    {
        Set-PSRepository -Name PSGallery -InstallationPolicy Trusted | Out-Null
        Install-Module -Name ImportExcel -Force | Out-Null
    }
    Import-Module ImportExcel | Out-Null
    $mod = get-module ImportExcel
    if ($mod -ne $null)
    {
        return $true
    }
}

Export-ModuleMember -function * -alias *