Error Exception calling ".ctor" with "2" argument(s) - azure

I'm getting below error while running a PowerShell script to connect to the ADX Cluster database.
Error:
New-Object: /home/anuruddha/kqltest.ps1:10
Line |
10 | $kcsb = New-Object Kusto.Data.KustoConnectionStringBuilder ($clusterU …
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Exception calling ".ctor" with "2" argument(s): "The type initializer for 'Kusto.Data.KustoConnectionStringBuilder' threw an exception."
Script:
$packagesRoot = "/home/user/tools/net472"
[System.Reflection.Assembly]::LoadFrom("$packagesRoot\Kusto.Data.dll")
$clusterUrl = "https://testcluster.kusto.windows.net;Fed=True"
$databaseName = "testdb"
$kcsb = New-Object Kusto.Data.KustoConnectionStringBuilder ($clusterUrl, $databaseName)
$Error[0].Exception.GetBaseException()|fl * -Force Output
Line |
9 | $kcsb = New-Object Kusto.Data.KustoConnectionStringBuilder ($clusterU …
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Exception calling ".ctor" with "2" argument(s): "The type initializer for 'Kusto.Data.KustoConnectionStringBuilder' threw an exception."
Message : Could not load file or assembly 'Kusto.Cloud.Platform, Version=11.0.0.0, Culture=neutral, PublicKeyToken=829a00acde12d551'. The system cannot find the file specified.
FileName : Kusto.Cloud.Platform, Version=11.0.0.0, Culture=neutral, PublicKeyToken=829a00acde12d551
FusionLog :
TargetSite :
Data : {}
InnerException :
HelpLink :
Source :
HResult : -2147024894
StackTrace :

Try passing only the URL to the constructor, then set the initial DB and security settings on the object afterwards:
$clusterUrl = "https://testcluster.kusto.windows.net"
$databaseName = "testdb"
$kcsb = New-Object Kusto.Data.KustoConnectionStringBuilder #($clusterUrl)
$kcsb.FederatedSecurity = $true
$kcsb.InitialCatalog = $databaseName

Related

Azure Function gives "InvokeMethodOnNull" error when calling Start-AzContainerGroup

I have a basic Azure Function running Powershell. I have followed instructions from the Microsoft Learn Tutorial to create an HTTP trigger to start a Container Instance. I have modified the tutorial after various attempts, so that the code now just starts an existing Container Instance on my Azure tenant, as follows:
using namespace System.Net
# Input bindings are passed in via param block.
param($Request, $TriggerMetadata)
# Write to the Azure Functions log stream.
Write-Host "PowerShell HTTP trigger function processed a request."
# Interact with query parameters or the body of the request.
$command = $Request.Query.Command
if (-not $command) {
$command = $Request.Body.Command
}
$body = "This HTTP triggered function executed successfully. Either pass 'start' or 'stop' as the 'command' parameter for the appropriate action to be executed on the acme-dns container."
if ($command) {
$body = "Command received: $command"
if ($command = "start") {
Start-AzContainerGroup -ResourceGroupName test -Name dev
}
elseif ($command = "stop") {
Stop-AzContainerGroup -ResourceGroupName test -Name dev
}
if ($?) {
$body = "This HTTP triggered function executed successfully. Started container group $name"
}
else {
$body = "There was a problem starting the container group."
}
}
# Associate values to output bindings by calling 'Push-OutputBinding'.
Push-OutputBinding -Name Response -Value ([HttpResponseContext]#{
StatusCode = [HttpStatusCode]::OK
Body = $body
})
requirements.psd1:
#{
# For latest supported version, go to 'https://www.powershellgallery.com/packages/Az'.
# To use the Az module in your function app, please uncomment the line below.
'Az' = '9.*'
}
Error text when I try to debug locally:
Azure Functions Core Tools
Core Tools Version: 4.0.4915 Commit hash: N/A (64-bit)
Function Runtime Version: 4.14.0.19631
Functions:
HttpExample: [GET,POST] http://localhost:7071/api/HttpExample
For detailed output, run func with --verbose flag.
[2022-12-13T14:27:14.456Z] Worker process started and initialized.
[2022-12-13T14:27:18.512Z] Host lock lease acquired by instance ID '0000000000000000000000000713F6BA'.
[2022-12-13T14:27:38.039Z] Executing 'Functions.HttpExample' (Reason='This function was programmatically called via the host APIs.', Id=5b3c9e21-290f-4ff4-ac49-21f362414926)
[2022-12-13T14:27:38.238Z] INFORMATION: PowerShell HTTP trigger function processed a request.
[2022-12-13T14:27:56.862Z] EXCEPTION: You cannot call a method on a null-valued expression.
[2022-12-13T14:27:56.863Z]
[2022-12-13T14:27:56.863Z] Exception :
[2022-12-13T14:27:56.864Z] Type : System.Management.Automation.ParentContainsErrorRecordException
[2022-12-13T14:27:56.865Z] Message : You cannot call a method on a null-valued expression.
[2022-12-13T14:27:56.866Z] HResult : -2146233087
[2022-12-13T14:27:56.867Z] CategoryInfo : InvalidOperation: (:) [], ParentContainsErrorRecordException
[2022-12-13T14:27:56.868Z] FullyQualifiedErrorId : InvokeMethodOnNull
[2022-12-13T14:27:56.869Z] InvocationInfo :
[2022-12-13T14:27:56.870Z] ScriptLineNumber : 1777
[2022-12-13T14:27:56.871Z] OffsetInLine : 13
[2022-12-13T14:27:56.872Z] HistoryId : -1
[2022-12-13T14:27:56.873Z] ScriptName : C:\Users\{USER}\Documents\PowerShell\Modules\Az.ContainerInstance\3.1.0\exports\ProxyCmdletDefinitions.ps1
[2022-12-13T14:27:56.874Z] Line : [Microsoft.WindowsAzure.Commands.Utilities.Common.AzurePSCmdlet]::PowerShellVersion = $Host.Runspace.Version.ToString()
[2022-12-13T14:27:56.875Z]
[2022-12-13T14:27:56.876Z] PositionMessage : At C:\Users\{USER}\Documents\PowerShell\Modules\Az.ContainerInstance\3.1.0\exports\ProxyCmdletDefinitions.ps1:1777 char:13
[2022-12-13T14:27:56.877Z] + [Microsoft.WindowsAzure.Commands.Utilities.Common.AzurePS .
[2022-12-13T14:27:56.878Z] + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[2022-12-13T14:27:56.879Z] PSScriptRoot : C:\Users\{USER}\Documents\PowerShell\Modules\Az.ContainerInstance\3.1.0\exports
[2022-12-13T14:27:56.880Z] PSCommandPath : C:\Users\{USER}\Documents\PowerShell\Modules\Az.ContainerInstance\3.1.0\exports\ProxyCmdletDefinitions.ps1
[2022-12-13T14:27:56.881Z] CommandOrigin : Internal
[2022-12-13T14:27:56.882Z] ScriptStackTrace : at Start-AzContainerGroup<Begin>, C:\Users\{USER}\Documents\PowerShell\Modules\Az.ContainerInstance\3.1.0\exports\ProxyCmdletDefinitions.ps1: line 1777
[2022-12-13T14:27:56.883Z] at <ScriptBlock>, C:\Coding\AzFunctions\PsHttpTrigger\HttpExample\run.ps1: line 20
[2022-12-13T14:27:56.884Z]
[2022-12-13T14:27:56.884Z]
[2022-12-13T14:27:56.913Z] Executed 'Functions.HttpExample' (Failed, Id=5b3c9e21-290f-4ff4-ac49-21f362414926, Duration=18894ms)
[2022-12-13T14:27:56.914Z] System.Private.CoreLib: Exception while executing function: Functions.HttpExample. System.Private.CoreLib: Result: Failure
Exception: You cannot call a method on a null-valued expression.
Stack: at System.Management.Automation.Runspaces.PipelineBase.Invoke(IEnumerable input)
[2022-12-13T14:27:56.914Z] at System.Management.Automation.Runspaces.Pipeline.Invoke()
[2022-12-13T14:27:56.915Z] at System.Management.Automation.PowerShell.Worker.ConstructPipelineAndDoWork(Runspace rs, Boolean performSyncInvoke)
[2022-12-13T14:27:56.916Z] at System.Management.Automation.PowerShell.Worker.CreateRunspaceIfNeededAndDoWork(Runspace rsToUse, Boolean isSync)
[2022-12-13T14:27:56.917Z] at System.Management.Automation.PowerShell.CoreInvokeHelper[TInput,TOutput](PSDataCollection`1 input, PSDataCollection`1 output, PSInvocationSettings settings)
[2022-12-13T14:27:56.917Z] at System.Management.Automation.PowerShell.CoreInvoke[TInput,TOutput](PSDataCollection`1 input, PSDataCollection`1 output, PSInvocationSettings settings)
[2022-12-13T14:27:56.918Z] at System.Management.Automation.PowerShell.Invoke[T](IEnumerable input, IList`1 output, PSInvocationSettings settings)
[2022-12-13T14:27:56.919Z] at System.Management.Automation.PowerShell.Invoke[T]()
[2022-12-13T14:27:56.919Z] at Microsoft.Azure.Functions.PowerShellWorker.PowerShell.PowerShellExtensions.InvokeAndClearCommands[T](PowerShell pwsh) in /mnt/vss/_work/1/s/src/PowerShell/PowerShellExtensions.cs:line 45
[2022-12-13T14:27:56.920Z] at Microsoft.Azure.Functions.PowerShellWorker.PowerShell.PowerShellManager.InvokeNonOrchestrationFunction(DurableController durableController, IDictionary outputBindings) in /mnt/vss/_work/1/s/src/PowerShell/PowerShellManager.cs:line 301
[2022-12-13T14:27:56.921Z] at Microsoft.Azure.Functions.PowerShellWorker.PowerShell.PowerShellManager.InvokeFunction(AzFunctionInfo functionInfo, Hashtable triggerMetadata, TraceContext traceContext, RetryContext retryContext, IList`1 inputData, FunctionInvocationPerformanceStopwatch stopwatch) in /mnt/vss/_work/1/s/src/PowerShell/PowerShellManager.cs:line 230
[2022-12-13T14:27:56.922Z] at Microsoft.Azure.Functions.PowerShellWorker.RequestProcessor.InvokeFunction(AzFunctionInfo functionInfo, PowerShellManager psManager, FunctionInvocationPerformanceStopwatch stopwatch, InvocationRequest invocationRequest) in /mnt/vss/_work/1/s/src/RequestProcessor.cs:line 336
[2022-12-13T14:27:56.923Z] at Microsoft.Azure.Functions.PowerShellWorker.RequestProcessor.ProcessInvocationRequestImpl(StreamingMessage request, AzFunctionInfo functionInfo, PowerShellManager psManager, FunctionInvocationPerformanceStopwatch stopwatch) in /mnt/vss/_work/1/s/src/RequestProcessor.cs:line 308.
It seems to me that the $Host variable within the AzurePS module is null, but I have no idea how to go about fixing this.
When I run the function from Azure cloud, it times out (Error: 500 - The request timed out. The web server failed to respond within the specified time.)
Running Start-AzContainerGroup from Powershell on my local PC works just fine.
I have modified your code accordingly for the requirement of Starting and stopping the Azure Container groups using PowerShell Azure Functions and it's working as expected:
using namespace System.Net
# Input bindings are passed in via param block.
param($Request, $TriggerMetadata)
# Write to the Azure Functions log stream.
Write-Host "PowerShell HTTP trigger function processed a request."
Connect-AzAccount -Tenant 'TeantId' -SubscriptionId 'SubscriptionId'
Set-AzContext -Subscription 'SubscriptionId'
$command = $Request.Query.Command
if (-not $command) {
$command = $Request.Body.Command
}
$body = "This HTTP triggered function executed successfully. Either pass 'start' or 'stop' as the 'command' parameter for the appropriate action to be executed on the acme-dns container."
if ($command) {
Write-Host "Command received: $command"
if ($command = "start") {
Start-AzContainerGroup -ResourceGroupName HariTestRG -Name test-cg
$body = "This HTTP triggered function executed successfully. Started container group."
}
elseif ($command = "stop") {
Stop-AzContainerGroup -ResourceGroupName HariTestRG -Name test-cg
$body = "This HTTP triggered function executed successfully. Stopped container group."
}
}
Push-OutputBinding -Name Response -Value ([HttpResponseContext]#{
StatusCode = [HttpStatusCode]::OK
Body = $body
})
Function API Response:
Result of Input Parameter to the Function API as Command = Start:
Before running this function, I have created the Container Group in Azure using these PowerShell Cmdlets:
$port1 = New-AzContainerInstancePortObject -Port 8000 -Protocol TCP
$port2 = New-AzContainerInstancePortObject -Port 8001 -Protocol TCP
$container = New-AzContainerInstanceObject -Name test-container -Image nginx -RequestCpu 1 -RequestMemoryInGb 1.5 -Port #($port1, $port2)
$containerGroup = New-AzContainerGroup -ResourceGroupName HariTestRG -Name test-cg -Location eastus -Container $container -OsType Linux -RestartPolicy "Never" -IpAddressType Public
Note: Few Parts of the above code taken from the MS Doc Reference 1 & 2.

Powershell 7 - Get-AzureADUser, AssignedLicenses, Convert Class to Object

When I retieve an AzureADUser while using the AzureAD module (imported with -UseWindowsPowershell), and trying to retrieve the property for AssignedLicenses, they return as a Class instead of an obect (e.g. just a string?)
class AssignedLicense {
DisabledPlans: System.Collections.Generic.List`1[System.String]
SkuId: zzzzzzzz-2c81-4ef7-yyyy-5b5392b571df}
class AssignedLicense {
DisabledPlans: System.Collections.Generic.List`1[System.String]
SkuId: zzzzzzz-fae0-4ca2-xxxx-7a907fd6c235
}
How would I convert such a thing to something I can actually use (e.g. an object?)
At first I thought it was JSON, but the ConvertFrom-JSON cmdlet gave errors on the notation, as far as I am aware there is no ConvertFrom-Class included in normal powershell :)
Did also try to just remove all the text and keep anything after SkuID, but that proves a challenge when the DisabledPlans is bigger/smaller than I expect.
Output received by running these commands:
$userList = Get-AzureADUser -filter "AccountEnabled eq true"
foreach ($u in $userList) {
$Assigned = ($u | Select-Object AssignedLicenses).AssignedLicenses
}
I tried to reproduce the scenario in my environment:
I tried the same script as yours:
$userList = Get-AzureADUser -filter "AccountEnabled eq true"
foreach ($u in $userList) {
$Assigned =($u | Select-Object AssignedLicenses ).AssignedLicenses
$Assigned
}
Getting expected result :
Alternately I tried with below commands:
$users = Get-AzureADUser -filter "AccountEnabled eq true"
$users | ForEach-Object {
foreach($user in $_.AssignedLicenses){
New-object -typename PSobject -property #{
ID = $_.Id
DisplayName = $_.DisplayName
DisabledPlans = $user.DisabledPlans
SkuId = $user.SkuId
}
}} | Sort-Object ID, DisplayName, DisabledPlans, SkuId | Export-Csv -Path C:\Assignedlicense2.csv -NoTypeInformation
I am getting the same result type for disabled plans System.Collections.Generic.List'1[System.String] as below image:
You can try the second way and check from your end or adding -join parameter to each object .
Reference: powershell - How to convert "System.Collections.Generic.List`1[System.String]" into readable format Using Get-AzureADMSConditionalAccessPolicy cmdlet - Stack Overflow
Or directly use:
$userList = Get-AzureADUser -filter "AccountEnabled eq true"
foreach ($u in $userList) {
$Assigned =$u.AssignedLicenses
$Assigned
}

Azure Powershell - Add User to Group, filtered by license

Been trying to create a Powershell script to achieve the following.
Check which users have a specific license assigned
assign these users to a specific security group.
Get-MsolUser | Where-Object {($_.licenses).AccountSkuId -match "DEVELOPERPACK_E5"} | Add-AzureADGroupMember -ObjectID c1ec272d-e0d2-496c-ba65-602e7d822c75
The first part of the script runs okay Get-MsolUser | Where-Object {($_.licenses).AccountSkuId -match "DEVELOPERPACK_E5"} which returns the users that have the license, however when trying to pipe results to "AddAzureADGroupMember" an error occurs.`
Error:
At line:1 char:1
+ Get-MsolUser | Where-Object {($_.licenses).AccountSkuId -match "DEVEL ...
+ ~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (Microsoft.Onlin...omation.GetUser:GetUser) [Get-MsolUser], PipelineStoppedException
+ FullyQualifiedErrorId : System.Management.Automation.PipelineStoppedException: The pipeline has been stopped.
at System.Management.Automation.CommandProcessor.ProcessRecord()
at System.Management.Automation.CommandProcessorBase.DoExecute()
at System.Management.Automation.Internal.Pipe.AddToPipe(Object obj)
at System.Management.Automation.Internal.Pipe.AddItems(Object objects)
at System.Security.SecurityContext.Run(SecurityContext securityContext, ContextCallback callback, Object state)
at System.Management.Automation.MshCommandRuntime.WriteObject(Object sendToPipeline, Boolean enumerateCollection)
at System.Management.Automation.Cmdlet.WriteObject(Object sendToPipeline, Boolean enumerateCollection)
at Microsoft.Online.Administration.Automation.MsolCmdlet.ProcessList(SearchDefinition searchDefinition, Int32 maxResultsSize) in X:\bt\1067178\repo\src\dev\PowerShell.V1\modules\psmodule\Cmdlets\MsolCmdlet.cs:line 372,Microsoft.Online.Administration.Automation.G
etUser
Add-AzureADGroupMember : Error occurred while executing AddGroupMember
Code: Request_BadRequest
Message: Invalid object identifier 'Microsoft.Online.Administration.User'.
RequestId: be0ee2c5-44e0-41f3-a9e2-f8396980cf6b
DateTimeStamp: Fri, 22 Oct 2021 10:37:21 GMT
HttpStatusCode: BadRequest
HttpStatusDescription: Bad Request
HttpResponseStatus: Completed
At line:1 char:86
+ ... PACK_E5"} | Add-AzureADGroupMember -ObjectId c1ec272d-e0d2-496c-ba65- ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Add-AzureADGroupMember], ApiException
+ FullyQualifiedErrorId : Microsoft.Open.AzureAD16.Client.ApiException,Microsoft.Open.AzureAD16.PowerShell.AddGroupMember```
The reason you are getting the error is you are not using the refobjectiD .
You can try to use the below cmdlt with foreach to achieve your requirement
Get-AzureADUser | Where-Object {($_.AssignedLicenses).SkuId -match "*******"} | ForEach-Object { Add-AzureADGroupMember -ObjectID ****** -RefObjectId $_.ObjectId}
Here is my output screenshots:
Managed to get this done with below, appreciate all help with this.
$Users = (Get-MsolUser | Where-Object {($_.licenses).AccountSkuId -match "DEVELOPERPACK_E5"}) | select -expand ObjectId
foreach ($User in $Users) {
Add-AzureADGroupMember -ObjectId 'c1eXXX2d-XXX2-496c-ba65-6XXXXXXXX5' -RefObjectId ($user)
}

Is it possible to share module between runspaces or assign a module to a runspace pool in Powershell?

I'm writing a multithreaded script which was leveraging the ability to multithread with runspaces and saving time until I had to use the Exchange module. It takes so long to load the Exchange module, it's almost as slow or slower than synchronous processing.
Below is the code I am working with, to repro you'll need to populate the servers array and the Exchange uri. At the bottom in quotes you can see the errors I'm receiving indicating the Exchange module is not being loaded and the Exchange cmdlets are not accessible.
Is there a way to copy the module to each new runspace and only initialize it one time or another way that I can significantly save time and reap the benefits of multiple runspaces with Exchange Powershell?
Get-Module | Remove-Module;
#Region Initial sessionstate
$servers = #("XXXXX", "XXXXX", "XXXXX");
$uri = 'https://XXXXX/powershell?ExchClientVer=15.1';
$session = new-pssession -ConfigurationName Microsoft.Exchange -ConnectionUri $uri -Authentication Negotiate;
$sessionImported = Import-PSSession $session -AllowClobber;
$sessionState = [System.Management.Automation.Runspaces.InitialSessionState]::Create($sessionImported);
$modules = Get-Module ;
foreach ($module in $modules)
{
if ($module.ExportedCommands.Keys -contains "get-mailbox")
{
$exchangeModule = $module;
}
}
$initialSessionState = [initialsessionstate]::CreateDefault()
$initialSessionState.ImportPSModule($exchangeModule)
#EndRegion Initial sessionstate
$RunspacePool = [runspacefactory]::CreateRunspacePool($initialSessionState);
$RunspacePool.Open();
foreach ($server in $servers)
{
$threads = New-Object System.Collections.ArrayList;
$PowerShell = [powershell]::Create($sessionState);
$PowerShell.RunspacePool = $RunspacePool;
[void]$PowerShell.AddScript({
Param ($server)
[pscustomobject]#{
server = $server
} | Out-Null
Set-ADServerSettings -ViewEntireForest:$true;
$mbs = Get-MailboxDatabase -Server $server -Status;
return $mbs;
}) # end of add script
$PowerShell.AddParameter('server', $server) | Out-Null;
$returnVal = $PowerShell.BeginInvoke();
$temp = "" | Select PowerShell,returnVal;
$temp.PowerShell = $PowerShell;
$temp.returnVal = $returnVal;
$threads.Add($Temp) | Out-Null;
} #foreach server
$completed = $false;
$threadsCompleted = New-Object System.Collections.ArrayList;
while ($completed -eq $false)
{
$completed = $true;
$threadsCompleted.Clear();
foreach ($thread in $threads)
{
$endInvoke = $thread.PowerShell.EndInvoke($thread.returnVal);
#$endInvoke;
$threadHandle = $thread.returnVal.AsyncWaitHandle.Handle;
$threadIsCompleted = $thread.returnVal.IsCompleted;
if ($threadIsCompleted -eq $false)
{
$completed = $false;
}
else
{
$threadsCompleted.Add($threadHandle) | Out-Null;
}
}
Write-Host "Threads completed count: " $threadsCompleted.Count;
foreach ($threadCompleted in $threadsCompleted)
{
Write-Host "Completed thread handle -" $threadCompleted;
}
#Write-Host "";
sleep -Milliseconds 1000;
} # while end
Write-Host "Seconds elapsed:" $stopwatch.Elapsed.TotalSeconds;
Write-Host "";
$temp.PowerShell.Streams.Error;
return;
Set-ADServerSettings : The term 'Set-ADServerSettings' is not
recognized as the name of a cmdlet, function, script file, or operable
program. Check the spelling of the name, or if a path was included,
verify that the path is correct and try again. At line:9 char:3
Set-ADServerSettings -ViewEntireForest:$true;
~~~~~~~~~~~~~~~~~~~~
CategoryInfo : ObjectNotFound: (Set-ADServerSettings:String) [], CommandNotFoundException
FullyQualifiedErrorId : CommandNotFoundException Get-MailboxDatabase : The term 'Get-MailboxDatabase' is not recognized
as the name of a cmdlet, function, script file, or operable program.
Check the spelling of the name, or if a path was included, verify that
the path is correct and try again. At line:10 char:10
$mbs = Get-MailboxDatabase -Server $server -Status;
~~~~~~~~~~~~~~~~~~~
CategoryInfo : ObjectNotFound: (Get-MailboxDatabase:String) [], CommandNotFoundException
FullyQualifiedErrorId : CommandNotFoundException
So the answer is yes, I found out that you can use a property from initialsessionstate called ImportPSModule (which can accept a known module name from a static module or a file path to a dynamic or custom module), the tricky thing with Exchange is that that the module is created dynamically. There is hope though, if you capture the module the way I do below, there is a property to it called "Path" which gives you a local file path to where the module is temporarily stored on the machine after it is created the first time during that particular session.
I also discovered that you can specify a list of commands you want to import (commented out below) which saves an enormous amount of time with importing the Exchange module if you only need a few commands. Literally the progress bar for the Exchange command import only flashes when you filter on only a few commands and if you were to blink you'd miss it. If you use the specific command code make sure to import the get-mailbox command as that's how I filter on which module is for Exchange on prem, and configure the uri to your environment.
The benchmark for the single threaded version of this was 106 seconds, the fastest I've seen my code process with runspaces and multithreading is 9.8 seconds, so the potential for processing time savings is significant.
$WarningPreference = "SilentlyContinue";
Get-Module | Remove-Module;
#Region Initial sessionstate
$uri = 'https://xxxxx/powershell?ExchClientVer=15.1';
$session = new-pssession -ConfigurationName Microsoft.Exchange -ConnectionUri $uri -Authentication Negotiate;
Import-PSSession $session -AllowClobber > $null;
#Import-PSSession $session -AllowClobber -CommandName Get-Mailbox, Get-MailboxDatabaseCopyStatus, Get-MailboxDatabase, Get-DatabaseAvailabilityGroup > $null;
$modules = Get-Module;
foreach ($module in $modules)
{
if ($module.ExportedCommands.Keys -contains "get-mailbox")
{
$exchangeModule = $module;
}
}
$maxThreads = 17;
$iss = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
[void]$iss.ImportPSModule($exchangeModule.Path)
$runspacePool = [runspacefactory]::CreateRunspacePool(1, $maxThreads, $iss, $host)
$runspacePool.Open()
#Region Get dag members
$PowerShell = [powershell]::Create($iss); # may not need a runspace here
$PowerShell.RunspacePool = $RunspacePool;
$PowerShell.AddCommand("get-databaseavailabilitygroup") | Out-Null;
$PowerShell.AddParameter("identity", $DagName) | Out-Null;
$returnVal = $PowerShell.Invoke(); # writes to screen
$servers = New-Object System.Collections.ArrayList;
$serversUnsorted = $returnVal.Servers | sort;
foreach ($server in $serversUnsorted)
{
$servers.Add($server) | Out-Null;
}
#EndRegion Get dag members
#EndRegion Initial sessionstate
foreach ($server in $servers)
{
$PowerShell = [powershell]::Create($iss);
$PowerShell.RunspacePool = $RunspacePool;
[void]$PowerShell.AddScript({
Param ($server)
[pscustomobject]#{
server = $server
} | Out-Null
Set-ADServerSettings -ViewEntireForest:$true;
$copyStatus = Get-MailboxDatabaseCopyStatus -Server $server;
return $copyStatus;
}) # end of add script
$PowerShell.AddParameter('server', $server) | Out-Null;
$returnVal = $PowerShell.BeginInvoke();
$temp = "" | Select PowerShell,returnVal;
$temp.PowerShell = $PowerShell;
$temp.returnVal = $returnVal;
$threads.Add($Temp) | Out-Null;
} #foreach server

Is there someone can tell me how to fix the Error "The remote server returned an error: (409) Conflict."

I use Automation Runbook to create the Azure Files' snapshot. And I get one error
Exception calling "Snapshot" with "0" argument(s): "The remote server returned an error: (409) Conflict." At line:3 char:1 + $snapshot = $share.Snapshot() + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : StorageException,
but it was not consistent.
I use the runbook to create the Azure Files snapshots. At first, it can work well, but recently there have some errors of "The remote server returned an error: (409) Conflict."
I use the code as below to create the snapshots everyday.
$context = New-AzureStorageContext -StorageAccountName "storage" -StorageAccountKey "********"
$share = Get-AzureStorageShare -Context $context -Name "test"
$snapshot = $share.Snapshot()
I want to fix the error.
Exception calling "Snapshot" with "0" argument(s): "The remote server returned an error: (409) Conflict." At line:3 char:1 + $snapshot = $share.Snapshot() + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : StorageException
As per discussed with Arthur, we try to use try-catch as a workaround since we didnot figure out the root cause.
when the create snapshot operation fails, then we can retry more times(like 3 times). The sample code like below:
$RetryIntervalInSeconds = 10
$NumberOfRetryAttempts = 2
$CmdOk = $False
do{
try{ *the code I using now $CmdOk = $True}
catch{ * the error I met $NumberOfRetryAttempts-- Start-Sleep -Seconds $RetryIntervalInSeconds }
}
while (-not $CmdOk -and $NumberOfRetryAttempts -ge 0)

Resources