Powershell 远程处理加速 Foreach 循环托管 Exchange

发布于 2024-11-16 11:55:51 字数 1808 浏览 6 评论 0原文

我有一个包含电子邮件地址和部门的 CSV 文件,需要在 Live@edu 上设置。我当前的命令看起来像这样:

Import-CSV departments.csv | ForEach-Object { Set-User $_.EmailAddress $_.Department }`

问题是,此操作需要永远。

我的第一个想法是,如果能够将 ForEach-Object 命令实际转发到远程计算机,这样就只需要在两台计算机之间创建一个管道,但是当我进入 PSSession,似乎没有任何可用的 foreach-object 。作为参考,我如何导入 PSSession 是:

Import-PSSession(New-PSSession -ConfigurationName Microsoft.Exchange `
    -ConnectionUri 'https://ps.outlook.com/powershell' `
    -Credential (Get-Credential) `
    -Authentication Basic -AllowRedirection)

是否有更好的方法可以导入会话以允许 ForEach-Object 是远程的,或者导入远程 foreach-object 的别名版本,也许作为 ForEach-Object-Remote ,或者也许有人有更好的建议来简化这个过程?

更新: 我尝试过的几件事:

  1. 在隐式远程命令上使用 -AsJob 开关。

    导入 CSV 部门.csv | ForEach-Object { 设置用户 $_.EmailAddress $_.Department -AsJob }
    

    不幸的是,这不起作用,因为存在不允许额外连接的限制。更糟糕的是,我什至不知道出了什么问题,直到我检查结果,发现其中很少有真正发生改变。

  2. 以不同的名称导入 ForEach-Object

    事实证明,添加前缀很容易,只需将 -Prefix RS 放入 Import-PSSession 命令中,即可使远程会话中的 ForEach-Object 等内容变为 < code>ForEach-RSObject 在本地会话中。不幸的是,这对我不起作用,因为我要连接的服务器没有可用的 Microsoft.Powershell ConfigurationName。

更新 2:Set-User cmdlet 似乎是 Microsoft 为 Live@edu 管理提供的。其目的是设置用户属性。它不是我能够调试的脚本或 cmdlet。不幸的是,它不接受管道输入,因此无法解决问题。

据我所知,问题在于每次运行此命令时它都必须构建和拆除到远程计算机的管道,而不是能够重用它。远程 ForEach 的想法允许我卸载该循环,以避免创建所有这些远程管道,而 -asJob 则允许它们全部并行运行。然而,它也导致错误默默地失败,并且只有少数记录真正得到正确更新。

我怀疑此时我将无法加快此命令的速度,但必须通过更好地跟踪我之前所做的事情来尽我所能来限制特定运行中需要更改的数据量(保留差异快照)。让工作变得有点困难。

编辑:启动自动化留下了非常有用的帮助,不幸的是,它们都不起作用。目前我的感觉是,除非我的提供商允许访问更多 powershell cmdlet,或者修改交换 cmdlet 以允许多个管道,否则我不会找到加快速度的方法,而我预计这两种情况都不会很快发生。我将他的答案标记为正确,尽管最终结果没有任何帮助。谢谢,启动自动化

I have a CSV of email adddresses and Departments that I need to set on Live@edu. The command I currently have looks something like this:

Import-CSV departments.csv | ForEach-Object { Set-User $_.EmailAddress $_.Department }`

The problem is, this operation takes FOREVER.

My first thought is that it would be great to have the ForEach-Object command actually be forwarded over to the remote machine, so that it will only need to create the one pipeline between the two machines, but when I go into the PSSession, there doesn't seem to be any foreach-object available. For reference, How I Import the PSSession is:

Import-PSSession(New-PSSession -ConfigurationName Microsoft.Exchange `
    -ConnectionUri 'https://ps.outlook.com/powershell' `
    -Credential (Get-Credential) `
    -Authentication Basic -AllowRedirection)

Is there a better way that I can import the session to allow ForEach-Object to be remote, or to import an aliased version of the remote foreach-object, perhaps as ForEach-Object-Remote, or perhaps does anybody have something better to suggest to streamline this process?

UPDATE:
A Couple Things I've tried:

  1. Using the -AsJob switch on the implicitly remoted command.

    Import-CSV departments.csv | ForEach-Object { Set-User $_.EmailAddress $_.Department -AsJob }
    

    This, unfortunately, doesn't work because there are throttling limits in place that don't allow the additional connections. Worse than that, I don't even know that anything went wrong until I check the results, and find that very few of them actually got changed.

  2. Importing the ForEach-Object under a different name.

    Turns out that adding a prefix is easy as putting -Prefix RS in the Import-PSSession Command to have things like the ForEach-Object from the Remote Session become ForEach-RSObject in the local session. Unfortunately, this won't work for me, because the server I'm connecting to does not does not have the Microsoft.Powershell ConfigurationName available to me.

UPDATE 2: The Set-User cmdlet seems to be Microsoft provided for Live@edu administration. Its purpose is to set User attributes. It is not a script or cmdlet that I am able to debug. It doesn't take pipeline input, unfortunately, so that would not be able to fix the issue.

As Far as I can tell, the problem is that it has to construct and tear down a pipeline to the remote machine every time this command runs, rather than being able to reuse it. The remote ForEach idea would have allowed me to offload that loop to avoid having to create all those remote pipelines, while the -asJob would have allowed them to all run in parallel. However, it also caused errors to fail silently, and only a few of the records actually get properly updated.

I suspect at this point that I will not be able to speed up this command, but will have to do whatever I can to limit the amount of data that needs to be changed in a particular run by keeping better track of what I have done before (keeping differential snapshots). Makes the job a bit harder.

EDIT: Start-Automate left a very useful help, unfortunately, neither of them work. It is my feeling at this point that I won't find a way to speed this up until my provider gives access to more powershell cmdlets, or the exchange cmdlets are modified to allow multiple pipelines, neither of which I expect to happen any time soon. I am marking his answer as correct, despite the ultimate result that nothing helps significantly. Thanks, Start-Automate.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

因为看清所以看轻 2024-11-23 11:55:51

您可以使用 foreach 语句而不是 Foreach-Object 来加快脚本速度,并避免尝试与服务器建立两个连接。

$departments = @(import-csv .\departments.csv)

foreach ($user in $departments) {
    Set-User $user.EmailAddress $user.Department 
} 

如果您需要批处理,您可以使用 for 语句,在每个批处理中前进

for ($i =0; $i -lt $departments.Count; $i+=3) {
     $jobs = @()
     $jobs+= Invoke-Command { Set-User $departments[$i].EmailAddress $departments[$i].Department } -AsJob
     $jobs+= Invoke-Command { Set-User $departments[$i + 1].EmailAddress $departments[$i + 1].Department } -AsJob
     $jobs+= Invoke-Command { Set-User $departments[$i + 2].EmailAddress $departments[$i + 2].Department } -AsJob
     $jobs | Wait-job | Receive-job
}

希望这有帮助

You can speed up your script and also avoid trying to make two connections to the server by the use of the foreach statement, instead of Foreach-Object.

$departments = @(import-csv .\departments.csv)

foreach ($user in $departments) {
    Set-User $user.EmailAddress $user.Department 
} 

If you need to batch, you could use the for statement, moving forward in each batch

for ($i =0; $i -lt $departments.Count; $i+=3) {
     $jobs = @()
     $jobs+= Invoke-Command { Set-User $departments[$i].EmailAddress $departments[$i].Department } -AsJob
     $jobs+= Invoke-Command { Set-User $departments[$i + 1].EmailAddress $departments[$i + 1].Department } -AsJob
     $jobs+= Invoke-Command { Set-User $departments[$i + 2].EmailAddress $departments[$i + 2].Department } -AsJob
     $jobs | Wait-job | Receive-job
}

Hope this helps

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文