1: param(
       2:     [string]$siteUrl,
       3:     [string]$login,
       4:     [string]$password
       5: )
       6:  
       7: $currentDir = Convert-Path(Get-Location)
       8: $dllsDir = resolve-path($currentDir +
       9:     "\Microsoft.SharePointOnline.CSOM.16.1.6420.1200\lib\net45")
      10:  
      11: [System.Reflection.Assembly]::LoadFile([System.IO.Path]::Combine($dllsDir,
      12:     "Microsoft.SharePoint.Client.dll"))
      13: [System.Reflection.Assembly]::LoadFile([System.IO.Path]::Combine($dllsDir,
      14:     "Microsoft.SharePoint.Client.Runtime.dll"))
      15:  
      16: if (-not $siteUrl)
      17: {
      18:     Write-Host "Specify site url in siteUrl parameter" -foregroundcolor red
      19:     return
      20: }
      21:  
      22: if (-not $login)
      23: {
      24:     Write-Host "Specify user name in login parameter" -foregroundcolor red
      25:     return
      26: }
      27:  
      28: if (-not $password)
      29: {
      30:     Write-Host "Specify user password in password parameter" -foregroundcolor red
      31:     return
      32: }
      33:  
      34: <#
      35: .Synopsis
      36:     Facilitates the loading of specific properties of a Microsoft.SharePoint.Client.ClientObject object or Microsoft.SharePoint.Client.ClientObjectCollection object.
      37: .DESCRIPTION
      38:     Replicates what you would do with a lambda expression in C#. 
      39:     For example, "ctx.Load(list, l => list.Title, l => list.Id)" becomes
      40:     "Load-CSOMProperties -object $list -propertyNames @('Title', 'Id')".
      41: .EXAMPLE
      42:     Load-CSOMProperties -parentObject $web -collectionObject $web.Fields -propertyNames @("InternalName", "Id") -parentPropertyName "Fields" -executeQuery
      43:     $web.Fields | select InternalName, Id
      44: .EXAMPLE
      45:    Load-CSOMProperties -object $web -propertyNames @("Title", "Url", "AllProperties") -executeQuery
      46:    $web | select Title, Url, AllProperties
      47: #>
      48: function Load-CSOMProperties {
      49:     [CmdletBinding(DefaultParameterSetName='ClientObject')]
      50:     param (
      51:         # The Microsoft.SharePoint.Client.ClientObject to populate.
      52:         [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0, ParameterSetName = "ClientObject")]
      53:         [Microsoft.SharePoint.Client.ClientObject]
      54:         $object,
      55:  
      56:         # The Microsoft.SharePoint.Client.ClientObject that contains the collection object.
      57:         [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0, ParameterSetName = "ClientObjectCollection")]
      58:         [Microsoft.SharePoint.Client.ClientObject]
      59:         $parentObject,
      60:  
      61:         # The Microsoft.SharePoint.Client.ClientObjectCollection to populate.
      62:         [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 1, ParameterSetName = "ClientObjectCollection")]
      63:         [Microsoft.SharePoint.Client.ClientObjectCollection]
      64:         $collectionObject,
      65:  
      66:         # The object properties to populate
      67:         [Parameter(Mandatory = $true, Position = 1, ParameterSetName = "ClientObject")]
      68:         [Parameter(Mandatory = $true, Position = 2, ParameterSetName = "ClientObjectCollection")]
      69:         [string[]]
      70:         $propertyNames,
      71:  
      72:         # The parent object's property name corresponding to the collection object to retrieve (this is required to build the correct lamda expression).
      73:         [Parameter(Mandatory = $true, Position = 3, ParameterSetName = "ClientObjectCollection")]
      74:         [string]
      75:         $parentPropertyName,
      76:  
      77:         # If specified, execute the ClientContext.ExecuteQuery() method.
      78:         [Parameter(Mandatory = $false, Position = 4)]
      79:         [switch]
      80:         $executeQuery
      81:     )
      82:  
      83:     begin { }
      84:     process {
      85:         if ($PsCmdlet.ParameterSetName -eq "ClientObject") {
      86:             $type = $object.GetType()
      87:         } else {
      88:             $type = $collectionObject.GetType() 
      89:             if ($collectionObject -is [Microsoft.SharePoint.Client.ClientObjectCollection]) {
      90:                 $type = $collectionObject.GetType().BaseType.GenericTypeArguments[0]
      91:             }
      92:         }
      93:  
      94:         $exprType = [System.Linq.Expressions.Expression]
      95:         $parameterExprType = [System.Linq.Expressions.ParameterExpression].MakeArrayType()
      96:         $lambdaMethod = $exprType.GetMethods() | ? { $_.Name -eq "Lambda" -and $_.IsGenericMethod -and $_.GetParameters().Length -eq 2 -and $_.GetParameters()[1].ParameterType -eq $parameterExprType }
      97:         $lambdaMethodGeneric = Invoke-Expression "`$lambdaMethod.MakeGenericMethod([System.Func``2[$($type.FullName),System.Object]])"
      98:         $expressions = @()
      99:  
     100:         foreach ($propertyName in $propertyNames) {
     101:             $param1 = [System.Linq.Expressions.Expression]::Parameter($type, "p")
     102:             try {
     103:                 $name1 = [System.Linq.Expressions.Expression]::Property($param1, $propertyName)
     104:             } catch {
     105:                 Write-Error "Instance property '$propertyName' is not defined for type $type"
     106:                 return
     107:             }
     108:             $body1 = [System.Linq.Expressions.Expression]::Convert($name1, [System.Object])
     109:             $expression1 = $lambdaMethodGeneric.Invoke($null, [System.Object[]] @($body1, [System.Linq.Expressions.ParameterExpression[]] @($param1)))
     110:  
     111:             if ($collectionObject -ne $null) {
     112:                 $expression1 = [System.Linq.Expressions.Expression]::Quote($expression1)
     113:             }
     114:             $expressions += @($expression1)
     115:         }
     116:  
     117:  
     118:         if ($PsCmdlet.ParameterSetName -eq "ClientObject") {
     119:             $object.Context.Load($object, $expressions)
     120:             if ($executeQuery) { $object.Context.ExecuteQuery() }
     121:         } else {
     122:             $newArrayInitParam1 = Invoke-Expression "[System.Linq.Expressions.Expression``1[System.Func````2[$($type.FullName),System.Object]]]"
     123:             $newArrayInit = [System.Linq.Expressions.Expression]::NewArrayInit($newArrayInitParam1, $expressions)
     124:  
     125:             $collectionParam = [System.Linq.Expressions.Expression]::Parameter($parentObject.GetType(), "cp")
     126:             $collectionProperty = [System.Linq.Expressions.Expression]::Property($collectionParam, $parentPropertyName)
     127:  
     128:             $expressionArray = @($collectionProperty, $newArrayInit)
     129:             $includeMethod = [Microsoft.SharePoint.Client.ClientObjectQueryableExtension].GetMethod("Include")
     130:             $includeMethodGeneric = Invoke-Expression "`$includeMethod.MakeGenericMethod([$($type.FullName)])"
     131:  
     132:             $lambdaMethodGeneric2 = Invoke-Expression "`$lambdaMethod.MakeGenericMethod([System.Func``2[$($parentObject.GetType().FullName),System.Object]])"
     133:             $callMethod = [System.Linq.Expressions.Expression]::Call($null, $includeMethodGeneric, $expressionArray)
     134:             
     135:             $expression2 = $lambdaMethodGeneric2.Invoke($null, @($callMethod, [System.Linq.Expressions.ParameterExpression[]] @($collectionParam)))
     136:  
     137:             $parentObject.Context.Load($parentObject, $expression2)
     138:             if ($executeQuery) { $parentObject.Context.ExecuteQuery() }
     139:         }
     140:     }
     141:     end { }
     142: }
     143:  
     144: function CheckMasterPage($ctx, $web)
     145: {
     146:     Load-CSOMProperties -object $web -propertyNames @("MasterUrl", "CustomMasterUrl",
     147:         "Webs", "AllProperties")
     148:     $ctx.ExecuteQuery()
     149:     
     150:     ($web.Url) | Out-File "log.txt" -Append
     151:     ("    " + $web.MasterUrl) | Out-File "log.txt" -Append
     152:     ("    " + $web.AllProperties["__InheritsMasterUrl"]) | Out-File "log.txt" -Append
     153:     ("    " + $web.CustomMasterUrl) | Out-File "log.txt" -Append
     154:     ("    " + $web.AllProperties["__InheritsCustomMasterUrl"]) | Out-File "log.txt" -Append
     155:     
     156:     foreach ($w in $web.Webs)
     157:     {
     158:         CheckMasterPage $ctx $w
     159:     }
     160: }
     161:  
     162: $securePassword = ConvertTo-SecureString $password -AsPlainText -Force
     163: $credentials =
     164:     New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($login,
     165:         $securePassword)    
     166: $ctx = New-Object Microsoft.SharePoint.Client.ClientContext($siteUrl)
     167: $ctx.AuthenticationMode =
     168:     [Microsoft.SharePoint.Client.ClientAuthenticationMode]::Default
     169: $ctx.Credentials = $credentials
     170: $ctx.Load($ctx.Site)
     171: $ctx.Load($ctx.Web)
     172: $ctx.ExecuteQuery()
     173:  
     174: CheckMasterPage $ctx $ctx.Web