Calling thread cannot access this object because a different thread owns it - 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

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.

PowerShell threading [duplicate]

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)

IIS 6 ServerBindings with WMI and Powershell v2

I've long had a bunch of VBS automations for IIS 6, including one that gets/sets complex server bindings on several farms of paired servers, each having dozens of apps, each app having 3-12 host headers. Each app has hostname, hostname-fullyqualified, and Disaster Recovery enabled hostname, so they can be a mess to maintain manually.
I did all my vbs stuff using ADSI, but I'm thinking WMI is probably more flexible than ADSI from a full server maintenance perspective. Please correct me if I'm wrong. So now I'm trying to move up to PowerShell + WMI to prepare for Windows 2008 + IIS 7.5. I'm enjoying the learning process, but I've hit a roadblock on this problem.
I can get/set all properties via WMI on my IIS 6 web servers, except ServerBindings. I feel like I'm close, but I'm missing some layer of containment, and I just can't get the objects I'm building to cast over to the right automation object.
The following code gets and reads the ServerBindings just fine. I simply can't figure out a way to write my changes back. Any advice is welcomed.
$objWMI = [WmiSearcher] "Select * From IISWebServerSetting"
$objWMI.Scope.Path = "\\" + $server + "\root\microsoftiisv2"
$objWMI.Scope.Options.Authentication = 6
$sites = $objWMI.Get()
foreach ($site in $sites)
{
$bindings = $site.psbase.properties | ? {$_.Name -contains "ServerBindings"}
foreach ($pair in $bindings.Value.GetEnumerator())
{
# The pair object is a single binding and contains the correct data
$pair
$pair.IP
$pair.Port
$pair.Hostname
# And this line will successfully erase the contents of
# the ServerBindings
$bindings.Value = #{}
# but I can't figure out what to do to update $bindings.Value
}
$site.Put()
}
I'm liking Powershell so far, so thanks for any help you're able to offer.
Alright. I got distracted with major disk failures. The fun never stops.
Anyway, the solution to this problem is simpler than I'd made it:
process
{
$bindings = $_.ServerBindings
foreach ($binding in $bindings)
{
$binding.IP = $ip
$binding.Port = $port
$binding.Hostname = $hostname
}
$_.ServerBindings = $bindings
$_.Put()
}
ServerBindings is an array, but it likes to be an array of its own kind. I was trying to build the array from scratch, but my home-rolled array didn't smell right to Powershell. So, pull the array out of ServerBindings into a new variable, manipulate the variable, then assign the manipulated variable back to the ServerBindings property. That keeps all the right typing in place. It's smooth as silk, and seems easier than ADSI.

Resources