Workflow error "unexpected Token" - powershell

I have the workflow below and I ge the error whenever I try to put it inside a workflow.
If I take it out of a workflow it works, I was wondering if there's some incorrect syntax I'm missing or even if this is not allowed n a workflow.
Apologies but my knowledge on workflows is limited (as you can probably tell). I'm ultimately trying to get the VMs to boot up in parallel.
workflow Set-AzureRmTags-and-Start {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$True)]
[string]$VmRG
)
$Start = Get-Date
Write-Output "Time is" $Start
$VmRGs = Get-AzureRmResourceGroup | Where-Object { $_.ResourceGroupName -like "*$VmRG*" }
foreach ($VmRG in $VmRGs) {
$VMs = Get-AzureRmVM -ResourceGroupName $VmRG.ResourceGroupName
ForEach ($vm in $vms) {
$tags2 = $_.Tags
$tags2 ['ShutdownSchedule_AllowStop'] = "$False";
}
Set-AzureRmResource -ResourceName $vm.Name -ResourceGroupName $vm.ResourceGroupName -ResourceType "Microsoft.Compute/virtualMachines" -Tag $tags2 -Force -Verbose
}
$Middle = Get-Date
Write-Output "Time Taken To Assign Tags" ($Middle - $Start).Minutes "Minutes"
ForEach -Parallel ($vm in $vms) {
Start-AzureRmVM -Name $vm.Name -ResourceGroupName $vm.ResourceGroupName -Verbose -Confirm:$false
}
$End = Get-Date
Write-Output "Time Taken To Start VMs" ($End - $Middle).Minutes "Minutes"
Write-Output "Total Time Taken" ($End - $Start).Minutes "Minutes"
}
The error is around ['ShutdownSchedule_AllowStop'] = "$False"; } Error "Unexpected Token in Expression or Statement".
Any ideas how I could correct this?
Thanks in advance.

$VmRGs = Get-AzureRmResourceGroup | Where-Object { $_.ResourceGroupName -like "*$VmRG*" }
foreach ($VmRG in $VmRGs) {
$VMs = Get-AzureRmVM -ResourceGroupName $VmRG.ResourceGroupName
ForEach ($vm in $vms) {
$tags2 = $_.Tags
$tags2 ['ShutdownSchedule_AllowStop'] = "$False";
}
Set-AzureRmResource -ResourceName $vm.Name -ResourceGroupName $vm.ResourceGroupName -ResourceType "Microsoft.Compute/virtualMachines" -Tag $tags2 -Force -Verbose
}
The line $tags2 = $_.Tags does not makes sense. There is no $_ at this point.
I don't have any experience in Azure tags, but the documentation here contains sample code that your code should more closely emulate. Setting tags in their samples always seems to use a HashTable construct, like #{ShutdownSchedule_AllowStop=$false}
This section seems relevant to what you're trying to accomplish:
To add tags to a resource group that has existing tags, retrieve the
existing tags, add the new tag, and reapply the tags:
$tags = (Get-AzureRmResourceGroup -Name examplegroup).Tags
$tags += #{Status="Approved"}
Set-AzureRmResourceGroup -Tag $tags -Name examplegroup
Up until now, I've never looked into workflows. After a little testing and a bit of research, it seems the 'unexpected Token' error is due the code existing in a workflow:
function Test-ArraySubscriptFn {
$tags2 = #{}
$tags2['asdf'] = $false
}
workflow Test-ArraySubscriptWf {
$tags2 = #{}
$tags2['asdf'] = $false # error: Only variable names may be used as the target of an assignment statement
$tags2.Add('asdf',$false) # error: Method invocation is not supported in a Windows Powershell Workflow...
$tags2 += #{'asdf'=$false} # no error
}
This is consistent with google search results. I guess we both need to do a bit of research on how workflows differ from 'regular' powershell scripts.

Related

Using pipelines within powershell for a loop failing with variable name Cannot validate argument on parameter

I am trying to change the property of one of the webapp configuration using a loop. The idea is to only change ones where the property is false. I have the code below, however it is failing with the error Cannot validate argument on parameter 'ResourceGroupName'
$is_https boolean
Get-AzSubscription | ForEach-Object {
Set-AzContext -SubscriptionName $_.Name
Get-AzWebApp | ForEach-Object {
$is_https =(Get-AzWebApp -ResourceGroupName $resourcegroup -Name $appName | select HttpsOnly).HttpsOnly
if ($webapp_https -eq $false )
{
Set-AzWebApp -ResourceGroupName $_.ResourceGroup -Name $_.Name -HttpsOnly $true
}
}
}
EDIT
I have now fixed the issue by adding a second foreach loop, however I would like there to be an If statement such that the Set-AzWebApp only runs if -httpsOnly is $false. At the moment it changes the setting for all web apps irrespective of whether it is required or not. The code snippet above doesnt work, however the below works as it doesnt have the if statement.
Get-AzSubscription | ForEach-Object {
Set-AzContext -SubscriptionName $_.Name
Get-AzWebApp | ForEach-Object {
Set-AzWebApp -ResourceGroupName $_.ResourceGroup -Name $_.Name -HttpsOnly $true
}
}
After reproducing from my end, I could achieve your requirement using the below script where the HttpsOnly sets when it is $false. Below is the complete script that worked for me where I have set the values at resource group level.
$AllWebApps=Get-AzWebApp -ResourceGroupName <RESOURCE_GROUP_NAME>
$AllWebApps
foreach($webapp in $AllWebApps)
{
$is_https = (Get-AzWebApp -Name $webapp.Name -ResourceGroupName $webapp.ResourceGroup).HttpsOnly
$is_https
if ($is_https -eq $false)
{
Set-AzWebApp -ResourceGroupName $webapp.ResourceGroup -Name $webapp.Name -HttpsOnly $true
}
}
Results:

If Statement not working as expected Powershell

I have put together the following script. What I would like to do is if the VM name is like DC or SQL then set the tag to $false or if it is anything else set the tag to $true.
If I take the If stateents out, it works fine, but it sets the DC and SQL tags to $true, I thought if I put in If ($vm.name -like *dc*) I could set the tag to $false, same for SQL.
[CmdletBinding()]
Param(
[Parameter(Mandatory=$True)]
[string]$RG
)
$rgs = Get-AzureRmResourceGroup | Where-Object {$_.ResourceGroupName -like "*$rg*"}
foreach ($rg in $rgs)
{
$vms = Get-AzureRmVm -ResourceGroupName $rg.ResourceGroupName
foreach ($vm in $vms)
{
if ($vm.Name -like *dc*)
{
$tags = $_.Tags
$tags['ShutdownSchedule_AllowStop'] = "$False";
Set-AzureRmResource -ResourceId $_.Id -Tag $tags -Force -Verbose
}
Elseif ($vm.Name -like *SQL*)
{
$tags = $_.Tags
$tags['ShutdownSchedule_AllowStop'] = "$False";
Set-AzureRmResource -ResourceId $_.Id -Tag $tags -Force -Verbose
}
Else
{
$tags = $_.Tags
$tags['ShutdownSchedule_AllowStop'] = "$True";
Set-AzureRmResource -ResourceId $_.Id -Tag $tags -Force -Verbose
}
}
}
The script that works is below
[CmdletBinding()]
Param(
[Parameter(Mandatory=$True)]
[string]$RG
)
$start = Get-Date
$rgs = Get-AzureRmResourceGroup | Where-Object {$_.ResourceGroupName -like "*$rg*"}
foreach ($rg in $rgs)
{
$vms = Get-AzureRmVm -ResourceGroupName $rg.ResourceGroupName
$vms.ForEach({
$tags = $_.Tags
$tags['ShutdownSchedule_AllowStop'] = "$True";
Set-AzureRmResource -ResourceId $_.Id -Tag $tags -Force -Verbose
})
}
The error I'm getting is around if ($vm.Name -like *dc*) Error is "You must provide value Expression following the * Operator" Same for SQL if.
And also an error (which has completely baffled me)
}
}
Last two lines erroring with "Unexpected token '}' in expression or statement"
Any help please before I crash google?
Thanks :)

Isolate Resource Group and Apply Tags

I'm trying to apply a set of tags to a particluar resource group, however it seems to target all the vms in the subscription. I'm sure I'm doing something silly, but been here for hours and now my heads starting to hurt.
The code I have is below.
Basically grab a resource group and within that resource group tag each vm.
$rgs = Get-AzureRmResourceGroup | where {$_.ResourceGroupName -like 'Linux-*'}
$rgs | Format-Table
foreach ($VMObjects in $rgs)
{
$VMObjects = Get-AzureRmVM
ForEach($vmobject in $vmobjects)
{
$tags2 =$VMObject.tags
$tags2 += #{ShutdownSchedule_Mis = "20:00->15:00" }
Set-AzureRmResource -ResourceName $vmobject.Name -ResourceGroupName $vmobject.ResourceGroupName -ResourceType "Microsoft.Compute/virtualMachines" -Tag $tags2 -Force -Verbose
}
}
Thanks in advance...
You are redifining your own variable $VMObjects, i dont think that is what you intend to do. You also forgot to scope Get-AzureRmVm to a current resource group. I would do it like this.
Get-AzureRmResourceGroup | Where-Object {$_.ResourceGroupName -like 'Linux-*'} | ForEach-Object {
$VMObjects = Get-AzureRmVM -ResourceGroupName $_.ResourceGroupName
ForEach ($vmobject in $vmobjects) {
$tags2 = $VMObject.tags
$tags2 += #{ShutdownSchedule_Mis = "20:00->15:00" }
Set-AzureRmResource -ResourceName $vmobject.Name -ResourceGroupName $vmobject.ResourceGroupName -ResourceType "Microsoft.Compute/virtualMachines" -Tag $tags2 -Force -Verbose
}
}

Get Vm's from RG with a particular tag value and update vm tags

I'm trying to do is check a tag from a RG which has been set to true, and then for those resources (vms) in the RG (which are currently set to $False) set those to true. I've got an update script
Trying to write an IF statement, which will pull outall tags which are set to true and then loop through the vms and set a tag on them to $true, bit stuck on the loop, if($OverRide -eq $true) {
Get-AzureRmVM .. thats about as far as I got :)
$x = Get-AzureRmVm -name "ThisVM" -ResourceGroupName "ThisRG"
$tags = $x.Tags
$tags['Shutdown'] = "$True"
$UpdateTag = Set-AzureRmResource -Tag $tags $x
But its how do i get the vms from the RG with override set to true and then loop through each vm setting it to false.
Trying to write an IF statement, which will pull outall tags which are set to true and then loop through the vms and set a tag on them to $true, bit stuck on the loop,
if($OverRide -eq $true) {
Get-AzureRmVm -ResourceGroupname | Where-Object { $_.Tags['ShutdownSchedule'] -eq $false } |`
ForEach-Object { $tags = $_.Tags; $tags['ShutdownSchedule'] = $true; `
$_ | Set-AzureRmResource -Tag $tags }
Hope that makes more sense
Update..
something like that, gets all RG's similar to This-RG and gets the RG name and then passes that into a loop catching all vm's
$resourcegroup = get-AzureRmResourceGroup | where -FilterScript {
$_.ResourceGroupName -like "This-RG*"
}
$rgname = $resourcegroup | select resourcegroupname
Get-AzureRmVm | foreach ($rgname in $rgnames)
{
Where-Object { $_.Tags['Shutdown'] -eq $false } | ForEach-Object`
{ $tags = $_.Tags; $tags['Shutdown'] = $true; $_ | Set-AzureRmResource -Tag $tags }
}
$resourceGroups = Get-AzureRmResourceGroups | Where-Object { $_.Tags['Shutdown'] -eq $false -and $_.Name -like 'This-RG*' }
$resourceGroups.ForEach({
$vms = Get-AzureRmVm -resourceGroup $_.Name
$vms.ForEach({
$tags = $_.Tags
$tags['Shutdown'] = $true;
Set-AzureRmResource -ResourceId $_.Id -Tag $tags
})
})
This will find all the resource groups with tag shutdown equals to false and change shutdown tag on all the vms inside those groups to true

$VM variable from whole subscription not resource group variable

I've been trying to specify and target machines within a resource group which is a vaiable.
The code I have is
[CmdletBinding()]
Param(
[Parameter(Mandatory=$True)]
[string]$RG
)
Get-AzureRmResourceGroup | Where-Object {$_.ResourceGroupName -like "*$rg*"}
foreach ($rg in $rgs)
{
$vms = Get-AzureRmVm -ResourceGroupName $_.ResourceGroupName
$vms.ForEach({
$tags = $_.Tags
$tags['ShutdownSchedule_AllowStop'] = "whatever";
Set-AzureRmResource -ResourceId $_.Id -Tag $tags -Force
})
}
When I run this I get the following
The variable '$_' cannot be retrieved because it has not been set.
At line:1 char:41
+ $vms = Get-AzureRmVm -ResourceGroupName $_.ResourceGroupName
However when I hardcode a name for $RG it seems to work.
Confused..
Any pointers please?
Thanks :)
Thats because you are confusing pipeline and for (x in b) constuct. you need to do:
$vms = Get-AzureRmVm -ResourceGroupName $rg.ResourceGroupName
$_ works inside pipeline, but in for loop you choose what to call the current iteration variable. in your case its $rg (foreach ($rg in $rgs))
ps. did i really type it wrong in that question? nope, i didnt ;)