Я написал сценарий с графическим интерфейсом для выполнения различных задач управления в SharePoint Online (SPO).
Один конкретный вызов API для получения групп SPO занимает много времени (примерно 150 секунд).Я проверил этот вызов с помощью командлетов SPO, а также вручную получил группы с помощью DLL-библиотек SharePoint, которые занимают примерно одинаковое время.Проблема в том, что запрос к SharePoint означает, что вам нужно запросить коллекцию групп, затем перейти к каждой группе в этой коллекции, перейти и получить ее.Это большой вызов, так как сайт SPO, с которым я работаю, имеет около 300 групп.
Чтобы ускорить вызов, у меня была идея асинхронно выполнять каждый вызов, чтобы все они отправлялись сразу (вместо этогоодного за другим).
Я использовал следующие ресурсы, чтобы найти решение: Адам, блог о автоматизаторах , этот ответ SO & этот блогпо ограничению выполнения задач .
Я обнаружил, что при реализации решений из первых двух источников код работал в тестовых сценариях, но не в основном решении.Я объяснил это тем, что PowerShell попросил назначить 300 различных процессов, и моя машина (хотя и мощная) быстро использовала ресурсы ЦП и ОЗУ.Поэтому я реализовал 3-й источник, чтобы ограничить число одновременно выполняемых задач.
Теперь, когда я вызываю API SPO, у меня возникает проблема, вызванная областью выполнения процесса.Чтобы использовать библиотеку PowerShell SPO (командлеты), вам необходимо вызвать функцию соединения, которая проверяет ваши учетные данные SPO и устанавливает соединение:
Connect-SPOService -Url https://$orgName.sharepoint.com/ -Credential $credentials
Вызов не будет работать, пока вы не вызовете это.
Давайте посмотрим на мою функцию:
function Get-Sharepoint-Groups-Async {
Begin {
$sw = [Diagnostics.Stopwatch]::StartNew()
Write-Debug ("Starting {0} " -f $MyInvocation.MyCommand)
#Create an hashtable variable
[hashtable]$Return = @{}
$Return.OutCode = 0
$Return.OutData = {}
$Return.OutDataShort = ""
}
Process {
try {
$web = $context.Web
$groupCollection = $web.SiteGroups
$context.Load($groupCollection)
$context.ExecuteQuery()
$jobs = @()
$maxConcurrentJobs = 25
foreach ($spGroup in $groupCollection) {
$Check = $false
while ($Check -eq $false) {
if ((Get-Job -State 'Running').Count -lt $maxConcurrentJobs) {
$jobs += Start-Job -ScriptBlock $sScriptBlock -ArgumentList @($groupTitle, $context)
$Check = $true #To stop endless looping and proceed to the next object in the list.
}
}
}
Wait-Job -Job $jobs | Out-Null
$results = Receive-Job -Job $jobs
$groups = @()
foreach ($job in $jobs) {
$group = New-Object PSObject
$group | Add-Member NoteProperty LoginName $job.LoginName
$group | Add-Member NoteProperty Title $job.Title
$group | Add-Member NoteProperty Users $job.Users
$group | Add-Member NoteProperty Roles $job.Roles
}
$Return.OutData = $groups
} catch {
Write-Error $Error.item(0)
$Return.OutCode = 2
$Return.OutData = $Error.item(0)
$Return.OutDataShort = $Error.item(0)
}
}
End {
$sw.Stop()
Write-Debug ("Ending {0} " -f $MyInvocation.MyCommand)
$outmsg = "Function: Get-SharePoint-Groups-Async took '$($sw.Elapsed.TotalSeconds)s' to execute."
Write-Host $outmsg
return $Return
}
}
Вот код $scriptBlock
, который выполняется:
$sScriptBlock = {
Param($spGroup, $context)
try {
Write-Host -ForegroundColor DarkGreen "Loading group: $($spGroup.Title)"
$context.Load($spGroup)
$context.ExecuteQuery()
$groupUsers = $spGroup.Users
$context.Load($groupUsers)
$context.ExecuteQuery()
#Get group users (easier to use cmdlet then query sp)
$spGroupUsers = Get-SPOUser -Site $Site -Group $spGroup.Title
$users = @()
foreach ($spUser in $spGroupUsers) {
$users += $spUser.LoginName
}
$group = New-Object PSObject
$group | Add-Member NoteProperty LoginName $spGroup.LoginName
$group | Add-Member NoteProperty Title $spGroup.Title
$group | Add-Member NoteProperty Users $users
$group | Add-Member NoteProperty Roles "Unknown"
return $group
} catch {
Write-Error $Error.item(0)
return $null
}
}
Независимо от того, что я делаю внутри блока выполнения, яне может использовать текущий контекст скрипта.Если я использую командлеты SPO, мне нужно каждый раз вызывать connect, что делает вызов настолько неэффективным, что синхронно выполнять его быстрее.Если я пытаюсь запросить API SPO с использованием контекста (который установлен в другом месте скрипта и работает везде), то я получаю сообщение об ошибке, говорящее, что методы не существуют.
Я не выполняю огромное количествоPowerShell, и я на самом деле не видел, чтобы люди делали это на SharePoint где-то еще, поэтому я немного застрял.
Есть какие-нибудь идеи о том, как я могу запрашивать SPO из моих фоновых задач, не вызывая connect каждый раз?
PS: Connect не возвращает ничего, что я могу передать этим процессам.