PowerShell threading [duplicate] - multithreading

I am trying to retrieve list of print queues from PowerShell as shown below.
But I am getting
The calling thread cannot access this object because a different thread owns it.
Is it happeneing because PowerShell not being able to support multiple threads?
Is there a way to get around this problem?

As far as I understand, you have to start PowerShell with -STA (single thread appartment) parameter to have your code working :
PowerShell -STA
Add-Type -AssemblyName "system.Printing"
$f = #([system.Printing.EnumeratedPrintQueueTypes]::local, [system.Printing.EnumeratedPrintQueueTypes]::shared)
$ps = New-Object system.Printing.localprintserver
$pq = $ps.GetPrintQueues($f)

Related

How to load > 1 million items to a SharePoint Online List

Can anyone suggest a reasonably practical and efficient way to load 1.2 million test items into a SharePoint Online list?
Background: We've decided to build a new application on top of SharePoint Online. Other application architecture options have all proved non-viable for various reasons. The application will use several SharePoint lists for persistence, one of which will be large, about 1.2 million items at peak. (Yes, we're planning ways to handle the 5000 item view limit.) To test viability of the architecture (including those view limit tactics) we need to create 1.2M test items in a list. Nothing we've tried has been practical:
Tried making POST calls to the REST API, with 5 concurrent threads so it will finish in a reasonable time. This fails after a bit with a HTTP 429 "Too many requests".
Tried uploading a spreadsheet with 1.2M rows. This fails at 130K entries each time, and I don't see a practical way to either upload / append to an existing list, nor to append items from one list to another existing list.
Tried running a Workflow (SharePoint 2013 variety, if that matters). This works but runs way too slow single threaded and I'm hesitant to try multiple concurrent workflows because this is a shared environment and if I trash the server that would be way not good.
Thanks in advance for any pointers!
You could try to use pnp powershell to add more than 1 million items.
$username = "amos#contoso.onmicrosoft.com"
$password = "password"
$cred = New-Object -TypeName System.Management.Automation.PSCredential -argumentlist $userName, $(convertto-securestring $Password -asplaintext -force)
Connect-PnPOnline -Url https://contoso.sharepoint.com/sites/dev -Credentials $cred
$ListName ="testn"
for($i=0;$i -lt 1000001;$i++){
Add-PnPListItem -List $ListName -Values #{"Title" = "test";}
}
Fastest way to load and process items from SPO using PnPPowershell goes something like following. Idea is to not initialize the items collection in any variable and directly process the items by page size.
Get-PnpListItem -List "{ListName}" -Fields "Field1","Field2","Fieldn" -PageSize 5000 | % {$i=0}{
% {$i=0}{
Do not move { to next line, I know it's weird but if you move, then good luck.
$item = $_
#Do your stuff with $item
Write-Host $item.Id
}

Powershell script only starts first VM in list

I have an Azure powershell script to start a list of VMs. When it runs it sucessfully starts the first VM in the list then nothing. No errors are reported, it appears to never return from the start command
Code as follows:
$vmList = "VM1", "VM2", "VM3"
Write-Output "Starting VMs in '$($AzureResourceGroup)' resource group";
Foreach ($vm in $vmList)
{
Write-Output "Starting VM...$vm"
$result = Start-AzureRmVM -Name $vm -ResourceGroupName AzureResourceGroup
Write-Output "Result of Start VM...$result"
}
When this run it outputs the "Starting VM....VM1", it starts the VM then nothing...
It sounds like your Start-AzureVM call is simply waiting for the VM to finish starting up.
That is, Start-AzureVm is by default a blocking, synchronous operation - despite its name[1]
To make it asynchronous, use the -AsJob switch, which uses a background job to start the VM; the call ends once that job has been created and returns a job object that you can use to track start-up progress later, via the usual *-Job cmdlets, such as Receive-Job.
[1] Regarding the name Start-AzureVM:
It is a misnomer in that PowerShell's nomenclature calls for the Start verb to exhibit asynchronous behavior:
From https://learn.microsoft.com/en-us/powershell/developer/cmdlet/approved-verbs-for-windows-powershell-commands (emphasis added):
Invoke vs. Start
The Invoke verb is used to perform an operation that is generally a synchronous operation, such as running a command. The Start verb is used to begin an operation that is generally an asynchronous operation, such as starting a process.
Note that the core Start-Sleep cmdlet is similarly misnamed.
With synchronous-by-default behavior, there is no good naming solution, because the name Invoke-AzureVm would be confusing.
The better approach - which would obviously be a breaking change - would have been to make the cmdlet asynchronous by default and offer a -Wait switch for to opt-into synchronous operation.

Wait to refresh external data connections in each sheet in Excel workbook before saving/closing using PowerShell

I've looked around quite a bit for solutions to this and don't see any PowerShell only solutions. I've seen a few PowerShell/VBA solutions but nothing saying it is not possible to complete solely using PowerShell. I would prefer not to use VBA if possible, PowerShell only.
I have a few workbooks with multiple sheets that are currently manually refreshed to retrieve data from a SQL Server (2008 R2) database instance. I can do everything I need using the following code if I run line by line and wait for refresh operations to complete:
$Excel = New-Object -ComObject Excel.Application
$Workbook = $Excel.Workbooks.Open('C:\test.xlsx')
$Excel.Visible = $True
$Workbook.RefreshAll()
$workbook.Save()
$Workbook.Close()
$Excel.Quit()
The only problem is when I run the whole script, as expected, the Save() method executes while the refresh operation is still running resulting in this prompt thus interrupting the Save(), Close(), and Quit() methods:
I could of course use the Start-Sleep cmdlet in a loop to wait for the database connections to complete using a static interval, however, the stored procedures that are executed range from 2 seconds - 3 minutes and seems like a waste of resources to sleep on each refresh like that.
The Stack Overflow answer I linked above lists 3 possible solutions to this but I don't see those properties that are listed available in the PowerShell objects (QueryTable.Refreshing for example doesn't exist using PowerShell). It appears that they're available in VBA, although the code examples are written using PowerShell. Are the examples wrong or am I missing something here?
My question: Is it possible to complete the code above by adding a dynamic 'wait' operation after RefreshAll() and before Save() using some sort of "Excel is refreshing/busy" property using PowerShell only?
I was able to figure this out with the following code additions:
$conn = $Workbook.Connections
and
while($conn | ForEach-Object {if($_.OLEDBConnection.Refreshing){$true}}){
Start-Sleep -Seconds 1
}
The Refreshing property lives in the OLEDBConnection object.
The final code:
$Excel = New-Object -ComObject Excel.Application
$Workbook = $Excel.Workbooks.Open('C:\test.xlsx')
$Excel.Visible = $True
$conn = $Workbook.Connections
$Workbook.RefreshAll()
while($conn | ForEach-Object {if($_.OLEDBConnection.Refreshing){$true}}){
Start-Sleep -Seconds 1
}
$workbook.Save()
$Workbook.Close()
$Excel.Quit()

powershell threading help using poshrsjob module

I am trying to multithread something and ran across this:
http://learn-powershell.net/2015/03/31/introducing-poshrsjob-as-an-alternative-to-powershell-jobs/
Attempting to use but getting errors and not able to access the data I need. Let me explain. I have an extremely simple example here:
#('12.34.56.78')|Start-RSJob -Name {"TEST_$($_)"} -ScriptBlock {
Param($Computername)
Test-Connection -ComputerName $Computername -Quiet
}
get-RSJob|Receive-RSJob
This actually errors saying computername is null. Any type of command I place in here same error comes up saying computername is null. How to get rid of this and how to access the Boolean value that should be returned.
This returns a true or false on the command line but I cannot access this value when run in this script.
Eventually this will need to take an array of IP's and I will need to access all values returned for each machine. I don't have to use this posh module but need threads and thought this a good choice. Any advice here is appreciated.
It looks like you found a bug in my module with using Param() to host the incoming data in the pipeline. Fortunately, you can work around this by just using $_ in the scriptblock.
#('12.34.56.78')|Start-RSJob -Name {"TEST_$($_)"} -ScriptBlock {
Test-Connection -ComputerName $_ -Quiet
}
get-RSJob|Receive-RSJob
That being said, I definitely need to stomp that bug.
Edit: The issue with returning a $False is a bug ($True returns fine) in Receive-RSJob. I'll fix that as well.

Calling thread cannot access this object because a different thread owns it

I am trying to retrieve list of print queues from PowerShell as shown below.
But I am getting
The calling thread cannot access this object because a different thread owns it.
Is it happeneing because PowerShell not being able to support multiple threads?
Is there a way to get around this problem?
As far as I understand, you have to start PowerShell with -STA (single thread appartment) parameter to have your code working :
PowerShell -STA
Add-Type -AssemblyName "system.Printing"
$f = #([system.Printing.EnumeratedPrintQueueTypes]::local, [system.Printing.EnumeratedPrintQueueTypes]::shared)
$ps = New-Object system.Printing.localprintserver
$pq = $ps.GetPrintQueues($f)

Resources