我已经编写了一个GUI脚本来在SharePoint Online(SPO)中执行各种管理任务。
一个特定的api调用来获取SPO组需要很长时间(大约150秒)。我已经使用SPO cmdlet测试了此调用,还使用SharePoint DLL手动获取了组,这两个过程大致相同。问题在于查询SharePoint意味着您需要询问组集合,然后在该集合中查找每个组,然后进行检索。这是一个很大的电话,因为我正在使用的SPO网站大约有300个小组。
为了加快通话速度,我想到了异步执行每个通话的想法,以使所有通话一次(而不是一个接一个)发送出去。
我使用以下资源提出了解决方案:Adam the automators blog,this SO answer和this blog on limiting no of executing tasks。
我从前两个来源实现解决方案时,代码在测试脚本中有效,但在主要解决方案中无效。我之所以要求PowerShell分配300个不同的进程,是因为我的计算机(虽然功能强大)很快就使CPU和RAM使用率最大化。因此,我实施了第3个源代码来限制我同时运行的任务数量。
现在,当我去调用SPO api时,进程执行范围会引起问题。要使用PowerShell SPO库(cmdlet),您需要调用connect函数,该函数会验证您的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 cmdlet,则每次都需要调用connect,这会使调用效率低下,因此同步进行会更快。如果我尝试使用上下文(在脚本的其他位置设置,并且可以在任何地方使用)查询SPO API,则会收到错误消息,指出方法不存在。
我并没有做太多的工作,我还没有真正看到人们在SharePoint上的其他地方这样做,所以我有点卡住了。
关于如何从后台任务中查询SPO而不每次都调用connect的任何想法?
PS:Connect不会返回我可以传递给这些进程的任何东西。