core/api/m365/SharePointOnline/csom/Invoke-MonkeyCSOMRequest.ps1
# Monkey365 - the PowerShell Cloud Security Tool for Azure and Microsoft 365 (copyright 2022) by Juan Garrido # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. Function Invoke-MonkeyCSOMRequest{ <# .SYNOPSIS Send requests using SharePoint client object model (CSOM) .DESCRIPTION Send requests using SharePoint client object model (CSOM) .INPUTS .OUTPUTS .EXAMPLE .NOTES Author : Juan Garrido Twitter : @tr1ana File Name : Invoke-MonkeyCSOMRequest Version : 1.0 .LINK https://github.com/silverhack/monkey365 #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "", Scope="Function")] [cmdletbinding()] Param ( [parameter(Mandatory=$True, HelpMessage="Authentication object")] [Object]$Authentication, [parameter(Mandatory=$false, HelpMessage="Endpoint")] [String]$Endpoint, [parameter(Mandatory=$false, HelpMessage="Select Object")] [String]$Select, [parameter(Mandatory=$false, HelpMessage="ContentType")] [String]$ContentType = "text/xml", [parameter(Mandatory=$false, HelpMessage="XML object data")] [Xml]$Data, [parameter(Mandatory=$false, HelpMessage="Get childitems")] [Switch]$ChildItems ) Begin{ #set null $raw_response = $url = $null #Set False $Verbose = $Debug = $False; $InformationAction = 'SilentlyContinue' if($PSBoundParameters.ContainsKey('Verbose') -and $PSBoundParameters.Verbose){ $Verbose = $True } if($PSBoundParameters.ContainsKey('Debug') -and $PSBoundParameters.Debug){ $Debug = $True } if($PSBoundParameters.ContainsKey('InformationAction')){ $InformationAction = $PSBoundParameters['InformationAction'] } if($null -eq $Authentication){ Write-Warning -Message ($message.NullAuthenticationDetected -f "SharePoint Online") break } #Get Authorization Header $AuthHeader = ("Bearer {0}" -f $Authentication.AccessToken) #Set Endpoint try{ if($Endpoint){ $Server = [System.Uri]::new($Endpoint) } else{ $Server = [System.Uri]::new($Authentication.resource) } } catch{ $msg = @{ MessageData = ($_.Exception.Message); callStack = (Get-PSCallStack | Select-Object -First 1); logLevel = 'verbose'; Verbose = $Verbose; Tags = @('SPSUrlError'); } Write-Verbose @msg return } #Set site path if($Server.Segments.Contains('sites/')){ $sitePath = ("{0}/_vti_bin/client.svc/ProcessQuery" -f $Server.AbsolutePath) #Remove double slashes $sitePath = [regex]::Replace($sitePath,"/+","/") } else{ $sitePath = ("/_vti_bin/client.svc/ProcessQuery") } #Get Url $url = [System.Uri]::new($Server,$sitePath) $url = $url.ToString() #Construct Request Header $requestHeader = @{"Authorization" = $AuthHeader} #Set new IDs $Id = Get-Random -Minimum 20000 -Maximum 50000 $opId = Get-Random -Minimum 20000 -Maximum 50000 #Set Array $Ids = New-Object System.Collections.Generic.List[Int32] $opIds = New-Object System.Collections.Generic.List[Int32] #Set count $count = 0 #Set Ids for Actions foreach ($elem in $Data.Request.Actions.GetEnumerator()){ if($elem.Name -eq 'ObjectPath'){ #Set Ids $elem.id = $Id.ToString() $elem.ObjectPathId = $opId.ToString() [void]$Ids.Add($Id); [void]$opIds.Add($opId); #Increment Id $Id+=1 $opId += 1 } if($elem.Name -eq 'Query'){ if($elem.ParentNode.FirstChild.Name -eq 'ObjectPath'){ #Set Ids $elem.id = $Id.ToString() #Add to Array [void]$Ids.Add($Id); try{ $opId = $opIds.Item($count-1) } catch{ $opId = Get-Random -Minimum 1 -Maximum 10 } $elem.ObjectPathId = $opId.ToString(); #Add to lopid #[void]$opIds.Add($opId); #Increment ObjectId $Id+=1 } else{ #Set Ids $elem.id = $Id.ToString() $elem.ObjectPathId = $opId.ToString() [void]$Ids.Add($Id); #Save OpId [void]$opIds.Add($opId); #Increment Id $Id+=1 $opId += 1 } } $count+=1 } #Set method $count = 0 #Save last OpId if($opIds.Count -eq 0){ [void]$opIds.Add($opId-1); } foreach ($elem in $Data.Request.ObjectPaths.GetEnumerator()){ if($null -ne $elem.PreviousSibling){ #Get parent Id if($null -ne $elem.PreviousSibling.PsObject.Properties.Item('ParentId')){ $Id = $elem.PreviousSibling.ParentId $elem.id = $Id.ToString() } else{ try{ $Id = $opIds.Item($count) } catch{ $Id = Get-Random -Minimum 1 -Maximum 10 $opIds.Add($Id) } #Add Id $elem.id = $Id.ToString() } } else{ #First #Get opId try{ $Id = $opIds.Item($count) } catch{ $Id = Get-Random -Minimum 1 -Maximum 10 $opIds.Add($Id) } #Add Id $elem.id = $Id.ToString() } if($null -ne $elem.Psobject.Properties.Item('ParentId')){ #Check if Id is in array if($elem.Id -in $opIds){ $_id = $elem.PreviousSibling | Select-Object -ExpandProperty Id -ErrorAction Ignore if($null -ne $_id){ $Id = $_id } else{ $Id = Get-Random -Minimum 1 -Maximum 10 } } else{ $Id = Get-Random -Minimum 1 -Maximum 10 } if($Id -ne $elem.Id){ try{ $elem.ParentId = $Id.ToString() } catch{ $Id = Get-Random -Minimum 1 -Maximum 10 $elem.ParentId = $Id.ToString() } } else{ $Id = Get-Random -Minimum 1 -Maximum 10 $elem.ParentId = $Id.ToString() } #$opids2+=$Id } $count+=1 } } Process{ if($null -ne $url){ #Get Data if($Data){ $param = @{ Url = $url; Headers = $requestHeader; Method = "POST"; ContentType = $ContentType; Data = $Data.OuterXml; UserAgent = $O365Object.UserAgent; Verbose = $Verbose; Debug = $Debug; InformationAction = $InformationAction; } } else{ $param = @{ Url = $url; Headers = $requestHeader; Method = "POST"; ContentType = $ContentType; UserAgent = $O365Object.UserAgent; Verbose = $Verbose; Debug = $Debug; InformationAction = $InformationAction; } } #Execute Query $tmp_response = Invoke-MonkeyWebRequest @param try{ if($null -ne $tmp_response){ if($null -eq $tmp_response.PsObject.Properties.Item('Length') -and $tmp_response -is [object]){ $errorData = $tmp_response[0] if($null -ne $errorData -and $null -ne $errorData.psobject.properties.Item('ErrorInfo') -and $null -ne $errorData.ErrorInfo){ $errorMessage = "{0} in {1}. {2} {3}" -f $errorData.ErrorInfo.ErrorTypeName, $Server.AbsoluteUri, $errorData.ErrorInfo.ErrorCode, $errorData.ErrorInfo.ErrorMessage $msg = @{ MessageData = ($message.SPSDetailedErrorMessage -f $errorMessage); callStack = (Get-PSCallStack | Select-Object -First 1); logLevel = 'verbose'; Verbose = $Verbose; Tags = @('SPSRequestError'); } Write-Verbose @msg } } else{ for($i=1;$i -lt $tmp_response.Length;$i++){ if($tmp_response[$i] -is [psobject]){ #Get object $raw_response = $tmp_response[$i] #check if childItems if($ChildItems){ if($null -ne $raw_response.PSObject.Properties.Item('_Child_Items_')){ $raw_response = $raw_response._Child_Items_ } } elseif($PSBoundParameters.ContainsKey('Select') -and $PSBoundParameters['Select']){ if($null -ne ($raw_response | Select-Object -ExpandProperty $PSBoundParameters['Select'] -ErrorAction Ignore)){ $raw_response = $raw_response.$($PSBoundParameters['Select']) #Check if child items if($null -ne $raw_response.PSObject.Properties.Item('_Child_Items_')){ $raw_response = $raw_response._Child_Items_ } } else{ $msg = @{ MessageData = ("Property {0} does not exist" -f $PSBoundParameters['Select']); callStack = (Get-PSCallStack | Select-Object -First 1); logLevel = 'verbose'; Verbose = $Verbose; Tags = @('SPSRequestError'); } Write-Verbose @msg } } } elseif($tmp_response[$i] -is [string]){ #Get object $raw_response = $tmp_response[$i] } } } } } catch{ $msg = @{ MessageData = ($message.UnableToProcessQuery -f $url); callStack = (Get-PSCallStack | Select-Object -First 1); logLevel = 'warning'; InformationAction = $InformationAction; Tags = @('SPSRequestError'); } Write-Warning @msg $msg = @{ MessageData = ($_); callStack = (Get-PSCallStack | Select-Object -First 1); logLevel = 'verbose'; Verbose = $Verbose; Tags = @('SPSRequestError'); } Write-Verbose @msg if($tmp_response -is [object]){ $errorData = $tmp_response[0] if($null -ne $errorData -and $null -ne $errorData.psobject.properties.Item('ErrorInfo') -and $null -ne $errorData.ErrorInfo){ $errorMessage = "[{0}][{1}]:[{2}]" -f $errorData.ErrorInfo.ErrorTypeName, $errorData.ErrorInfo.ErrorCode, $errorData.ErrorInfo.ErrorMessage $msg = @{ MessageData = ($message.SPSDetailedErrorMessage -f $errorMessage); callStack = (Get-PSCallStack | Select-Object -First 1); logLevel = 'verbose'; Verbose = $Verbose; Tags = @('SPSRequestError'); } Write-Verbose @msg } } } } } End{ if($raw_response){ return $raw_response } } } |