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 :)
Related
I'm trying to alter a data source for a set of Reporting Services reports, but I can't get the Powershell to work for them. I'd appreciate any help :)
$server = "http://My/ReportServer/"
$dataSource = Get-RsDataSource -Path "/Data Sources/NewDataSource" -
ReportServerUri $server
$reports = Get-RsCatalogItems -RsFolder "/Testing/NewDataSOurce" -ReportServerUri $server -Recurse | Where-Object {$_.TypeName -eq "Report"}
$reports | ForEach-Object {
$reportDataSource = Get-RsItemDataSource -RsItem $_.Path -ReportServerUri $server
$reportPath = $_.Path
if ($reportDataSource.Name -eq "OldDataSource") {
Set-RsItemDataSource -RsItem $reportPath -DataSource $dataSource -ReportServerUri $server
}
}
I wrote a function to do what you are talking about for setting data sources. Here is what I have... Unfortunately I don't have a SSRS instance any longer. The full script / module is on a gist on my GitHub account. I'll paste my gist urls at the bottom on this thread.
The function that I'm pulling the snippet out of is called Deploy-NativeSSRS. I used this module + a driver script to push items that had been checked out of TFS. So they could in turn be parsed and then pushed to SSRS during CI activities.
$reports = New-ReportObject -files (Get-ChildItem -Path $reportPath -Filter $reportExtension)
foreach($report in (($reports | Where-Object{$_.datasourcename -eq $datasourceName}).filename))
{
$fileExt = $reportExtension.trim('*')
$status = Set-SSRSDataSourceInfoNative -ReportName ($report.trim($fileext)) -reportPath $documentLibrary -DataSourceName $datasourceName -DataSourcePath "$dataSourceTarget/$datasourceName" -reportWebService $webservice
write-output "The following $report datasource was updated to $datasourcename"
}
function set-SSRSDataSourceInfoNative
{
param
(
[parameter(mandatory)]
[string]$Reportname, #with no extension SSRS has no name for the file in native mode
[parameter(mandatory)]
[string]$reportPath,
[parameter(mandatory)]
[string]$DataSourceName,
[parameter(mandatory)]
[string]$DataSourcePath,
[parameter(mandatory)]
[uri]$reportWebService,
[System.Management.Automation.PSCredential]$Credentials
)
if ($Credentials)
{$reportProxy = new-webserviceproxy -uri $reportWebService -Credential $credentials -namespace 'SSRSProxy' -class 'ReportService2010'}
else
{$reportProxy = new-webserviceproxy -uri $reportWebService -UseDefaultCredential -namespace 'SSRSProxy' -class 'ReportService2010'}
$f = $ReportName.ToLower()
try
{
$dataSources = $reportProxy.GetItemDataSources("$reportpath/$reportname")
}
catch
{
"Error was $_"
$line = $_.InvocationInfo.ScriptLineNumber
"Error was in Line $line"
"ReportName: $reportname"
"ReportPath: $reportpath"
}
$proxyNameSpace = $dataSources.gettype().Namespace
$dc = $reportProxy.GetDataSourceContents($DataSourcePath)
if ($dc)
{
$d = $dataSources | Where-Object {$_.name -like $DataSourceName }
$newDataSource = New-Object ("$proxyNameSpace.DataSource")
$newDataSource.Name = $datasourcename
$newDataSource.Item = New-Object ("$proxyNamespace.DataSourceReference")
$newDataSource.Item.Reference = $DatasourcePath
$d.item = $newDataSource.item
$reportProxy.SetItemDataSources("$reportpath/$f", $d)
$set = ($reportproxy.GetItemDataSources("$reportPath/$f")).name
write-verbose "$reportname set to data source $set"
$returnobj = 'success'
}
$returnobj
}
https://gist.github.com/crshnbrn66/40c6be436e7c2e69b4de5cd625ce0902
https://gist.github.com/crshnbrn66/b10e43ef0dadf7f4eeae620428b2cdd9
Here something that works with Power BI Report Server Rest API:
[string] $uri = "https://xxx/Reports"
$session = New-RsRestSession -ReportPortalUri $uri
$reports = Get-RsRestFolderContent -WebSession $session -RsFolder / -Recurse | Where-Object {$_.Type -eq "PowerBIReport"}
$reports | ForEach-Object {
$dataSources = Get-RsRestItemDataSource -WebSession $session -RsItem $_.Path | Where-Object {$_.ConnectionString -eq "yyy;zzz"}
#$dataSources[0].DataModelDataSource.AuthType = 'Windows'
$dataSources[0].DataModelDataSource.Username = 'domain\user'
$dataSources[0].DataModelDataSource.Secret = 'password'
Set-RsRestItemDataSource -WebSession $session -RsItem $_.Path -RsItemType 'PowerBIReport' -DataSources $dataSources
}
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.
I have the below script which I had help with from here, one quick question how do you I set $MyVar as variable, and a wildcard so partial name can be selected.
Select-AzureRmSubscription -SubscriptionName "MySubscription"
Get-AzureRmResourceGroup | Where-Object {$_.ResourceGroupName -like '$MyVar'} | ForEach-Object {
$VMs = Get-AzureRmVM -ResourceGroupName $_.ResourceGroupName
ForEach ($vm in $vms) {
$tags2 = $VM.tags
$tags2 += #{ShutdownSchedule_AllowStart="True"; ShutdownSchedule_AllowStop="True" }
Set-AzureRmResource -ResourceName $vm.Name -ResourceGroupName $vm.ResourceGroupName -ResourceType "Microsoft.Compute/virtualMachines" -Tag $tags2 -Force -Verbose
}
}
Not sure how to set it as a variable. Was thinking maybe {$_.ResourceGroupName -like $('$MyVar')}
Or do I need to set it as a parameter, as in a workflow, but not sure how to do that outside a workflow..
Use double quotes so the variable can be expanded (see about_quoting_rules), then add * to either end (or both) you want to wildcard:
{$_.ResourceGroupName -like "*$MyVar*"}
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
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 ;)