Reputation: 1336
I have a bunch of VMs in Azure I want to run the same script against. Because of reasons, I can't use powershell 7, so I have to use powershell 5. Which means I can use "foreach -parallel", but NOT "foreach-parallel". So it can work, but requires a workflow.
I have the following workflow that will grab the list of servers in a specific tenant/environment, and then run a foreach -parallel to run a script against each of them at the same time.
The problem I'm running into is that it appears to work, but the result I get out is:
Microsoft.Azure.Commands.Compute.Automation.Models.PSRunCommandResult
blah
Which is not the actual result (in this it would be the time). Because it's within a workflow, getting the details out is... painful. How do I get the results? It appears to run, there's no errors, but I can't figure out the results. Thanks.
The get-member on $out gives:
Name MemberType Definition
---- ---------- ----------
GetType Method type GetType()
ToString Method string ToString(), string ToString(string format, System.IFormatProvider formatProvider), string IFormattable.ToString(string format, System.I...
PSComputerName NoteProperty string PSComputerName=localhost
PSShowComputerName NoteProperty bool PSShowComputerName=True
PSSourceJobInstanceId NoteProperty guid PSSourceJobInstanceId=0870d1ff-1234-5678-014e-2e123456c7d8
Capacity Property System.Int32 {get;set;}
Count Property System.Int32 {get;set;}
EndTime Property {get;set;}
Error Property {get;set;}
Item Property {get;set;}
Name Property {get;set;}
Output Property {get;set;}
StartTime Property {get;set;}
Status Property System.String {get;set;}
Value Property Deserialized.System.Collections.Generic.List`1[[Microsoft.Azure.Management.Compute.Models.InstanceViewStatus, Microsoft.Azure.Management.Compu...
Microsoft.Azure.Commands.Compute.Automation.Models.PSRunCommandResult
And here's the script I'm running:
#for some reason you need to disconnect from one and then connect to the other, can't run two at once.
disconnect-azaccount
connect-azaccount -Tenant "mytenantid"
#get all the dev Windows VM servers in the current tenant that are turned on.
$serverinfo = @()
Get-AzContext -ListAvailable |where-object {$_.Name -like "*Dev*"}| %{
$_|select-azcontext
$serverinfo += get-azvm -status | Where-Object {$_.PowerState -eq "VM running" -and $_.StorageProfile.OSDisk.OSType -eq "Windows"}
}
#honestly, for the test I filtered down to the jumpboxes.
$serverinfo2 = $serverinfo|where {$_.Name -like "*jumpbox*"}
#workflows are needed; can't run foreach -parallel otherwise.
Workflow TestParallel{
#need to pass in the details, it can't reach the $serverinfo2 otherwise.
param($listofservers) #take serverinfo2 and make it accessible from within the workflow.
$test=@()
#need to set the proper context
Get-AzContext -ListAvailable |where-object {$_.Name -like "*Dev*"}| select-azcontext
#now we run each of these at the same time. Foreach-parallel requires 7, but we can do foreach -parallel within powershell 4 workflows.
Foreach -parallel($server in $listofservers){
#now that the script is on there, run the command locally.
$out = Invoke-AzVMRunCommand `
-ResourceGroupName $server.ResourceGroupName `
-Name $server.name `
-CommandId 'RunPowerShellScript' `
-ScriptString "$dt = gwmi win32_localtime; New-Object DateTime $dt.year,$dt.month,$dt.day,$dt.hour,$dt.minute, $dt.second"
#scriptstring is a newer command, added in july 2022
#Formating the Output with the VM name. Value[0].Message contains the results from running the script.
#export it to a variable that will survive the foreach
#$WORKFLOW:test += $server.Name + " " + $out.Value[0].Message
$WORKFLOW:test += $out.Value[1].Message #appears to be 1 now, using " -scriptstring"
#writing it locally to see if it shows up
"$out"
}
[array]$resultsArray = @($test)
write-output ("blah " + $test[0])
$resultsArray
}
TestParallel $serverinfo2
Upvotes: 0
Views: 911
Reputation: 3484
I would avoid using "foreach -parallel" and "workflow" because of current limitations w.r.t parallel processing and workflows that are mentioned here so I would recommend to try foreach loop for all VMs using first approach mentioned in this answer i.e., to store the script in storage account and then run that script remotely in all VMs using Invoke-AzVMRunCommand cmdlet with the help of foreach loop which basically runs the script in all VMs.
Upvotes: 0