Export List of teams users to CSV, then check user modifications

I am triying to compare diferences between a saved copy and a copy in RAM of the list of Teams users (MicrosoftTeams ps module)

I would like to get just the modified objects when I run compare-object

$CsOnlineUserList = Get-CsOnlineUser -ResultSize ([int32]::MaxValue) |select displayname,userprincipalname,SipAddress,Identity,StateorProvince,city,State,company,InterpretedUserType,Hostingprovider,enterprisevoiceenabled,lineuri,CallingLineIdentity,OnlineVoiceRoutingPolicy,DialPlan,TenantDialPlan,TeamsUpgradePolicy,TeamsUpgradeEffectiveMode
$CsOnlineUserList | Export-Csv -NoTypeInformation -Path ("CsOnlineUserList.csv")

#$CsOnlineUserList |Export-Csv -NoTypeInformation -Path ("TEMPCsOnlineUserList.csv")
#$CsOnlineUserList = (Import-Csv -Path ("TEMPCsOnlineUserList.csv"))

$CachedCsOnlineUserList = (Import-Csv -Path ("CsOnlineUserList.csv") |select displayname,userprincipalname,SipAddress,Identity,StateorProvince,city,State,company,InterpretedUserType,Hostingprovider,enterprisevoiceenabled,lineuri,CallingLineIdentity,OnlineVoiceRoutingPolicy,DialPlan,TenantDialPlan,TeamsUpgradePolicy,TeamsUpgradeEffectiveMode)

$ModifiedObjList2 = Compare-Object -ReferenceObject $CachedCsOnlineUserList -DifferenceObject $CsonlineuserList -Property displayname,userprincipalname,SipAddress,Identity,StateorProvince,city,State,company,InterpretedUserType,Hostingprovider,enterprisevoiceenabled,lineuri,CallingLineIdentity,OnlineVoiceRoutingPolicy,DialPlan,TenantDialPlan,TeamsUpgradePolicy,TeamsUpgradeEffectiveMode


$CsOnlineUserList.count
$CachedCsOnlineUserList.count
$ModifiedObjList2.count

For some reason the only way I can get compare-object to do what it is supposed to is to export the variable into CSV file, then import it again from CSV into the same variable (commented lines)

Is there a better way to do this?

At least there is a better way of formatting such code. If you have very long lists making your code hard to read you can outsource those long lists to separate variables. Here is an example:

$PropertyList =
'displayname',
'userprincipalname',
'SipAddress',
'Identity',
'StateorProvince',
'city',
'State',
'company',
'InterpretedUserType',
'Hostingprovider',
'enterprisevoiceenabled',
'lineuri',
'CallingLineIdentity',
'OnlineVoiceRoutingPolicy',
'DialPlan',
'TenantDialPlan',
'TeamsUpgradePolicy',
'TeamsUpgradeEffectiveMode'

$CsOnlineUserList = 
    Get-CsOnlineUser -ResultSize ([int32]::MaxValue) |
        Select-Object -Property $PropertyList

This way you don’t have to scroll horizontally. :wink:

But regardless of that I don’t get what you’re actually trying to do. You compare the list you just created with itself?! Why? :thinking:

And of course there will be differences because an export to a CSV file looses all type information of the properties. If you want to save these as well you would need to use Export-CliXml instead. :point_up_2:t4:

I’m not sure if Compare-Object is supposed to do what you think it is. :wink: In the vast majority of the cases I know of we compare only on one or two properties - not on all of them.

Yes, I am trying to compare the list with itself, but I will generate CsOnlineUserList.csv today and compare it tomorrow

if you run the code as it is i would expect compare-object to say all properties haven’t modified, but instead, it says all objects are modified
Unless I export the variable to CSV and then reimport the saved file like in the commented lines, then it will say no objects are modified

I am not comparing all properties, I am comparing only the properties I need to check modifications for

When i use export/import cli-xml i get the same behavior

$PropertyList =
'displayname',
'userprincipalname',
'SipAddress',
'Identity',
'StateorProvince',
'city',
'State',
'company',
'InterpretedUserType',
'Hostingprovider',
'enterprisevoiceenabled',
'lineuri',
'CallingLineIdentity',
'OnlineVoiceRoutingPolicy',
'DialPlan',
'TenantDialPlan',
'TeamsUpgradePolicy',
'TeamsUpgradeEffectiveMode'

$CsOnlineUserList = 
    Get-CsOnlineUser -ResultSize ([int32]::MaxValue) |
        Select-Object -Property $PropertyList


$CsOnlineUserList | Export-CliXml -Path ("CsOnlineUserList.xml")

#$CsOnlineUserList |Export-CliXml -NoTypeInformation -Path ("TEMPCsOnlineUserList.xml")
#$CsOnlineUserList = (Import-Clixml -Path ("TEMPCsOnlineUserList.xml"))

$CachedCsOnlineUserList = (Import-Clixml -Path ("CsOnlineUserList.xml") |Select-Object -Property $PropertyList)

$ModifiedObjList2 = Compare-Object -ReferenceObject $CachedCsOnlineUserList -DifferenceObject $CsonlineuserList -Property $PropertyList


$CsOnlineUserList.count
$CachedCsOnlineUserList.count
$ModifiedObjList2.count

OK. And what do you expect to be changed from yesterday to today? :wink:

As I already said I usually compare objects only for one or two property. For example: If I’m only interessted in added or removed users I’d pick the userprincipalname to be compared and maybe use the parameters -IncludeEqual and -PassThru to still have the list complete but with additional information about who’s been added and who’s been removed.

I did some modifications because I don’t have access to an Azure tenant at the moment and to be a little easier to digest and tested your code.

I did this:

$SearchBase = 
    'OU=Users,OU=18thFloor,OU=Office,OU=Berlin,OU=Germany,DC=contoso,DC=de'

$PropertyList =
'DisplayName',
'userprincipalname',
'GivenName',
'Surname',
'Enabled'

$CsOnlineUserList = 
    Get-ADUser -Filter * -SearchBase $SearchBase -Properties DisplayName |
        Select-Object -Property $PropertyList

$CsOnlineUserList | 
    Export-CliXml -Path '.\CsOnlineUserList.xml'

Now I deactivated one user account and continued with this:

$CsOnlineUserList | 
    Export-CliXml -Path '.\TEMPCsOnlineUserList.xml'

$CsOnlineUserList = 
    Import-Clixml -Path '.\TEMPCsOnlineUserList.xml' | 
        Select-Object -Property $PropertyList

$CachedCsOnlineUserList = 
    Import-Clixml -Path '.\CsOnlineUserList.xml' | 
        Select-Object -Property $PropertyList

$CompareObjectSplat = @{
    ReferenceObject  = $CachedCsOnlineUserList
    DifferenceObject = $CsonlineuserList
    Property         = $PropertyList
    IncludeEqual     = $True
    PassThru         = $True
}

$ModifiedObjList2 = 
    Compare-Object @CompareObjectSplat

$ModifiedObjList2 | 
    Format-Table -AutoSize

… and I got exactly the expected result. All user accounts have been the same except for one. The one was listed twice. Once for the ReferenceObject side and once for the DifferenceObjct side.