I created VSTS Task Group with Azure Powershell Task Inline Script with Four Parameters. I have added this Task Group to Release Definition and configured parameters. When i try to release it failed with following error
2018-03-23T10:28:42.2811600Z ##[error]At
C:\Users\buildguest\AppData\Local\Temp\6e927620-8956-47d6-b926-00d9177a4c26.ps1:2
char:9
+ [String] Container-Service,
+ ~ Parameter declarations are a comma-separated list of variable names with optional initializer expressions.
At
C:\Users\buildguest\AppData\Local\Temp\6e927620-8956-47d6-b926-00d9177a4c26.ps1:2
char:9
+ [String] Container-Service,
+ ~ Missing ')' in function parameter list.
Here is Azure Powershell Script
Param(
[String] $(apiManagementRg),
[String] $(apiManagementName),
[String] $(swaggerUrl),
[String] $(basePath),
[String] $(apiId)
)
$ApiMgmtContext = New-AzureRmApiManagementContext -ResourceGroupName $(apiManagementRg) -ServiceName $(apiManagementName)
Import-AzureRmApiManagementApi -Context $ApiMgmtContext -SpecificationFormat "Swagger" -SpecificationUrl $(swaggerUrl) -Path $(basePath) -ApiId $(apiId)
Release Definition Screenshot
Release Definition
It's mainly caused by the PowerShell script syntax errors.
Based on your script, it seems $(apiManagementRg), $(apiManagementName), $(swaggerUrl), $(basePath) and $(apiId) are variables defined in your release definition.
To use the user defined variables from the release definition into Powershell script parameters, you should specify the user defined variables in Script Arguments to pass the values into your PowerShell parameters.
Detail steps as below:
Remove the task group you created.
Re-create task group with Azure PowerShell Task as below:
Inline Script:
Param(
[String] $Rg,
[String] $Name,
[String] $Url,
[String] $path,
[String] $apiId
)
$ApiMgmtContext = New-AzureRmApiManagementContext -ResourceGroupName $Rg -ServiceName $Name
Import-AzureRmApiManagementApi -Context $ApiMgmtContext -SpecificationFormat "Swagger" -SpecificationUrl $url -Path $path -ApiId $apiId
Script Arguments:
-Rg "$(apiManagementRg)" -Name "$(apiManagementName)" -Url "$(swaggerUrl)" -path "$(basePath)" -apiId "$(apiId)"
Related
I need to add the Outbound IPs of Azure Function-App to Azure KeyVault Firewall Rule to be whitelisted, using powershell, to be executed on a pipeline. My script is :
param(
[Parameter()]
[String]$resourcegrp,
[String]$funcname,
[String]$kv
)
$functionApp = Get-AzFunctionApp -ResourceGroupName $resourcegrp -Name $funcname
Add-AzKeyVaultNetworkRule -VaultName $kv -ResourceGroupName $resourcegrp `
-IpAddressRange ($functionApp.PossibleOutboundIPAddress).Trim()
Update-AzKeyVaultNetworkRuleSet -VaultName $kv -ResourceGroupName $resourcegrp `
-DefaultAction Deny -Bypass AzureServices `
-IpAddressRange ($functionApp.PossibleOutboundIPAddress).Trim()
The above is giving below error:
where as if I do the same on powershell prompt like below, it works fine.
Can someone suggest what's wrong in my PS1 file, or what can be a better way to achieve the same with a PowerShell script.
This is because the property $functionApp.PossibleOutboundIPAddress is a single string
$functions[0].PossibleOutboundIPAddress | gm
TypeName: System.String
But Add-AzKeyVaultNetworkRule expects a string array
Get-Help Add-AzKeyVaultNetworkRule -Parameter ipaddressrange
-IpAddressRange <System.String[]>
Specifies allowed network IP address range of network rule.
You should be able to make this work by splitting the value from the functionApp on the , delimiter
$addAzKeyVaultNetworkRuleSplat = #{
VaultName = $kv
ResourceGroupName = $resourcegrp
IpAddressRange = $functionApp.PossibleOutboundIPAddress -split ','
}
Add-AzKeyVaultNetworkRule #addAzKeyVaultNetworkRuleSplat
I have created a number of Global Parameters in DEV Azure Data Factory which is being used in many pipelines. I have deployed those Global parameters using ARM template to our QA environment.
Now I have deleted few parameters from Dev environment and when I re deployed the ARM template, those parameters are not getting deleted from QA environment.
I did not find any other way to delete from QA environment as we do not have delete permissions in QA.
Can you please suggest what are the next steps? I am looking for a powershell command way to delete those parameters.
param
(
[parameter(Mandatory = $true)] [String] $globalParametersFilePath,
[parameter(Mandatory = $true)] [String] $resourceGroupName,
[parameter(Mandatory = $true)] [String] $dataFactoryName
)
Import-Module Az.DataFactory
$newGlobalParameters = New-Object 'system.collections.generic.dictionary[string,Microsoft.Azure.Management.DataFactory.Models.GlobalParameterSpecification]'
Write-Host "Getting global parameters JSON from: " $globalParametersFilePath
$globalParametersJson = Get-Content $globalParametersFilePath
Write-Host "Parsing JSON..."
$globalParametersObject = [Newtonsoft.Json.Linq.JObject]::Parse($globalParametersJson)
# $gp in $factoryFileObject.properties.globalParameters.GetEnumerator())
# may be used in case you use non-standard location for global parameters. It is not recommended.
foreach ($gp in $globalParametersObject.GetEnumerator()) {
Write-Host "Removing global parameter:" $gp.Key
$globalParameterValue = $gp.Value.ToObject([Microsoft.Azure.Management.DataFactory.Models.GlobalParameterSpecification])
$newGlobalParameters.Remove($gp.Key)
}
$dataFactory = Get-AzDataFactoryV2 -ResourceGroupName $resourceGroupName -Name $dataFactoryName
$dataFactory.GlobalParameters = $newGlobalParameters
Write-Host "Updating" $newGlobalParameters.Count "global parameters."
Set-AzDataFactoryV2 -InputObject $dataFactory -Force
I have a script that I can run remotely via Invoke-Command
Invoke-Command -ComputerName (Get-Content C:\Scripts\Servers.txt) `
-FilePath C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1
As long as I use default parameters, it works fine. However, the script has 2 named [switch] parameters (-Debug and -Clear)
How can I pass the switched parameters via the Invoke-Command? I've tried the -ArgumentList but I'm getting errors so I must have the syntax wrong or something. Any help is greatly appreciated.
-ArgumentList is based on use with scriptblock commands, like:
Invoke-Command -Cn (gc Servers.txt) {param($Debug=$False, $Clear=$False) C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 } -ArgumentList $False,$True
When you call it with a -File it still passes the parameters like a dumb splatted array. I've submitted a feature request to have that added to the command (please vote that up).
So, you have two options:
If you have a script that looked like this, in a network location accessible from the remote machine (note that -Debug is implied because when I use the Parameter attribute, the script gets CmdletBinding implicitly, and thus, all of the common parameters):
param(
[Parameter(Position=0)]
$one
,
[Parameter(Position=1)]
$two
,
[Parameter()]
[Switch]$Clear
)
"The test is for '$one' and '$two' ... and we $(if($DebugPreference -ne 'SilentlyContinue'){"will"}else{"won't"}) run in debug mode, and we $(if($Clear){"will"}else{"won't"}) clear the logs after."
Without getting hung up on the meaning of $Clear ... if you wanted to invoke that you could use either of the following Invoke-Command syntaxes:
icm -cn (gc Servers.txt) {
param($one,$two,$Debug=$False,$Clear=$False)
C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 #PSBoundParameters
} -ArgumentList "uno", "dos", $false, $true
In that one, I'm duplicating ALL the parameters I care about in the scriptblock so I can pass values. If I can hard-code them (which is what I actually did), there's no need to do that and use PSBoundParameters, I can just pass the ones I need to. In the second example below I'm going to pass the $Clear one, just to demonstrate how to pass switch parameters:
icm -cn $Env:ComputerName {
param([bool]$Clear)
C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 "uno" "dos" -Debug -Clear:$Clear
} -ArgumentList $(Test-Path $Profile)
The other option
If the script is on your local machine, and you don't want to change the parameters to be positional, or you want to specify parameters that are common parameters (so you can't control them) you will want to get the content of that script and embed it in your scriptblock:
$script = [scriptblock]::create( #"
param(`$one,`$two,`$Debug=`$False,`$Clear=`$False)
&{ $(Get-Content C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 -delimiter ([char]0)) } #PSBoundParameters
"# )
Invoke-Command -Script $script -Args "uno", "dos", $false, $true
PostScript:
If you really need to pass in a variable for the script name, what you'd do will depend on whether the variable is defined locally or remotely. In general, if you have a variable $Script or an environment variable $Env:Script with the name of a script, you can execute it with the call operator (&): &$Script or &$Env:Script
If it's an environment variable that's already defined on the remote computer, that's all there is to it. If it's a local variable, then you'll have to pass it to the remote script block:
Invoke-Command -cn $Env:ComputerName {
param([String]$Script, [bool]$Clear)
& $ScriptPath "uno" "dos" -Debug -Clear:$Clear
} -ArgumentList $ScriptPath, (Test-Path $Profile)
My solution to this was to write the script block dynamically with [scriptblock]:Create:
# Or build a complex local script with MARKERS here, and do substitutions
# I was sending install scripts to the remote along with MSI packages
# ...for things like Backup and AV protection etc.
$p1 = "good stuff"; $p2 = "better stuff"; $p3 = "best stuff"; $etc = "!"
$script = [scriptblock]::Create("MyScriptOnRemoteServer.ps1 $p1 $p2 $etc")
#strings get interpolated/expanded while a direct scriptblock does not
# the $parms are now expanded in the script block itself
# ...so just call it:
$result = invoke-command $computer -script $script
Passing arguments was very frustrating, trying various methods, e.g.,
-arguments, $using:p1, etc. and this just worked as desired with no problems.
Since I control the contents and variable expansion of the string which creates the [scriptblock] (or script file) this way, there is no real issue with the "invoke-command" incantation.
(It shouldn't be that hard. :) )
I suspect its a new feature since this post was created - pass parameters to the script block using $Using:var. Then its a simple mater to pass parameters provided the script is already on the machine or in a known network location relative to the machine
Taking the main example it would be:
icm -cn $Env:ComputerName {
C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 -one "uno" -two "dos" -Debug -Clear $Using:Clear
}
I needed something to call scripts with named parameters. We have a policy of not using ordinal positioning of parameters and requiring the parameter name.
My approach is similar to the ones above but gets the content of the script file that you want to call and sends a parameter block containing the parameters and values.
One of the advantages of this is that you can optionally choose which parameters to send to the script file allowing for non-mandatory parameters with defaults.
Assuming there is a script called "MyScript.ps1" in the temporary path that has the following parameter block:
[CmdletBinding(PositionalBinding = $False)]
param
(
[Parameter(Mandatory = $True)] [String] $MyNamedParameter1,
[Parameter(Mandatory = $True)] [String] $MyNamedParameter2,
[Parameter(Mandatory = $False)] [String] $MyNamedParameter3 = "some default value"
)
This is how I would call this script from another script:
$params = #{
MyNamedParameter1 = $SomeValue
MyNamedParameter2 = $SomeOtherValue
}
If ($SomeCondition)
{
$params['MyNamedParameter3'] = $YetAnotherValue
}
$pathToScript = Join-Path -Path $env:Temp -ChildPath MyScript.ps1
$sb = [scriptblock]::create(".{$(Get-Content -Path $pathToScript -Raw)} $(&{
$args
} #params)")
Invoke-Command -ScriptBlock $sb
I have used this in lots of scenarios and it works really well.
One thing that you occasionally need to do is put quotes around the parameter value assignment block. This is always the case when there are spaces in the value.
e.g. This param block is used to call a script that copies various modules into the standard location used by PowerShell C:\Program Files\WindowsPowerShell\Modules which contains a space character.
$params = #{
SourcePath = "$WorkingDirectory\Modules"
DestinationPath = "'$(Join-Path -Path $([System.Environment]::GetFolderPath('ProgramFiles')) -ChildPath 'WindowsPowershell\Modules')'"
}
Hope this helps!
This is an unfortunate situation. Positional parameters work.
# test.ps1
param($myarg1, $myarg2, $myarg3)
"myarg1 $myarg1"
"myarg2 $myarg2"
"myarg3 $myarg3"
# elevated prompt
invoke-command localhost test.ps1 -args 1,$null,3
myarg1 1
myarg2
myarg3 3
Or you can hardcode a default.
# test2.ps1
param($myarg='foo2')
dir $myarg
invoke-command localhost test2.ps1
Cannot find path 'C:\Users\js\Documents\foo2' because it does not exist.
Or copy the script there:
$s = New-PSSession localhost
copy-item test2.ps1 $home\documents -ToSession $s
icm $s { .\test2.ps1 -myarg foo3 }
Cannot find path 'C:\Users\js\Documents\foo3' because it does not exist.
I have written a powershell script which takes multiple webapps(comma separated) as input.
I am splitting these webapps using powershell split function and configuring webapps by traversing each one of them using for-each loop.
Everything works fine in Powershell editor but when I configure the same script to VSTS release pipeline , split function doesn't work and which results in failure.
Input : devopstestwebapp1,devopstestwebapp2
Code : $WebAppName = $WebAppName.Split(',')
Output (After Split) : devopstestwebapp1 devopstestwebapp2
Error : The Resource 'Microsoft.Web/sites/devopstestwebapp1
devopstestwebapp2' under resource group 'DevOpsResourseGroup' was not found.
Following is my powershell script
# Parameters
param (
[Parameter(Position=0,mandatory=$true)]
[string] $AADAppID,
[Parameter(Position=1,mandatory=$true)]
[string] $AADKey,
[Parameter(Position=2,mandatory=$true)]
[string] $TenantId,
[Parameter(Position=3,mandatory=$true)]
[string] $ResourceGroupName,
[Parameter(Position=4,mandatory=$true)]
[string] $ServerName,
[Parameter(Position=5,mandatory=$true)]
[string] $RGLocation,
[Parameter(Position=6,mandatory=$true)]
[string] $WebAppName,
[Parameter(Position=7,mandatory=$true)]
[string] $SubscriptionName
)
# Connect to Azure
$ssAADKey = ConvertTo-SecureString $AADKey -AsPlainText -Force
$psCredential = New-Object System.Management.Automation.PSCredential($AADAppID, $ssAADKey)
Connect-AzureRmAccount -ServicePrincipal -Credential $psCredential -Subscription $SubscriptionName -TenantId $TenantId
write-host $WebAppName
$WebAppName = $WebAppName.Split(',')
write-host $WebAppName
Foreach ($servicename in $WebAppName)
{
write-host $servicename
}
Below works perfectly with VSTS powershell task :
Store app name in variable :
$WebAppName = '$(WebAppName)'
write-host $WebAppName
foreach($servicename in $WebAppName.Split(','))
{
write-host $servicename
}
Output :
2019-04-22T11:02:02.7680996Z devopstestwebapp1,devopstestwebapp2,devopstestwebapp3
2019-04-22T11:02:02.7737101Z devopstestwebapp1
2019-04-22T11:02:02.7750490Z devopstestwebapp2
2019-04-22T11:02:02.7765756Z devopstestwebapp3
The problematic line is this one:
$WebAppName = $WebAppName.Split(',')
You are reassigning the result of split to the same variable $WebAppName which has been declared as a string in the parameter list. So the array result of Split will be cast to a string, not an array anymore.
The solution is to assign the result of split to a new variable:
$WebAppNameSplit = $WebAppName.Split(',')
I have a script that I can run remotely via Invoke-Command
Invoke-Command -ComputerName (Get-Content C:\Scripts\Servers.txt) `
-FilePath C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1
As long as I use default parameters, it works fine. However, the script has 2 named [switch] parameters (-Debug and -Clear)
How can I pass the switched parameters via the Invoke-Command? I've tried the -ArgumentList but I'm getting errors so I must have the syntax wrong or something. Any help is greatly appreciated.
-ArgumentList is based on use with scriptblock commands, like:
Invoke-Command -Cn (gc Servers.txt) {param($Debug=$False, $Clear=$False) C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 } -ArgumentList $False,$True
When you call it with a -File it still passes the parameters like a dumb splatted array. I've submitted a feature request to have that added to the command (please vote that up).
So, you have two options:
If you have a script that looked like this, in a network location accessible from the remote machine (note that -Debug is implied because when I use the Parameter attribute, the script gets CmdletBinding implicitly, and thus, all of the common parameters):
param(
[Parameter(Position=0)]
$one
,
[Parameter(Position=1)]
$two
,
[Parameter()]
[Switch]$Clear
)
"The test is for '$one' and '$two' ... and we $(if($DebugPreference -ne 'SilentlyContinue'){"will"}else{"won't"}) run in debug mode, and we $(if($Clear){"will"}else{"won't"}) clear the logs after."
Without getting hung up on the meaning of $Clear ... if you wanted to invoke that you could use either of the following Invoke-Command syntaxes:
icm -cn (gc Servers.txt) {
param($one,$two,$Debug=$False,$Clear=$False)
C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 #PSBoundParameters
} -ArgumentList "uno", "dos", $false, $true
In that one, I'm duplicating ALL the parameters I care about in the scriptblock so I can pass values. If I can hard-code them (which is what I actually did), there's no need to do that and use PSBoundParameters, I can just pass the ones I need to. In the second example below I'm going to pass the $Clear one, just to demonstrate how to pass switch parameters:
icm -cn $Env:ComputerName {
param([bool]$Clear)
C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 "uno" "dos" -Debug -Clear:$Clear
} -ArgumentList $(Test-Path $Profile)
The other option
If the script is on your local machine, and you don't want to change the parameters to be positional, or you want to specify parameters that are common parameters (so you can't control them) you will want to get the content of that script and embed it in your scriptblock:
$script = [scriptblock]::create( #"
param(`$one,`$two,`$Debug=`$False,`$Clear=`$False)
&{ $(Get-Content C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 -delimiter ([char]0)) } #PSBoundParameters
"# )
Invoke-Command -Script $script -Args "uno", "dos", $false, $true
PostScript:
If you really need to pass in a variable for the script name, what you'd do will depend on whether the variable is defined locally or remotely. In general, if you have a variable $Script or an environment variable $Env:Script with the name of a script, you can execute it with the call operator (&): &$Script or &$Env:Script
If it's an environment variable that's already defined on the remote computer, that's all there is to it. If it's a local variable, then you'll have to pass it to the remote script block:
Invoke-Command -cn $Env:ComputerName {
param([String]$Script, [bool]$Clear)
& $ScriptPath "uno" "dos" -Debug -Clear:$Clear
} -ArgumentList $ScriptPath, (Test-Path $Profile)
My solution to this was to write the script block dynamically with [scriptblock]:Create:
# Or build a complex local script with MARKERS here, and do substitutions
# I was sending install scripts to the remote along with MSI packages
# ...for things like Backup and AV protection etc.
$p1 = "good stuff"; $p2 = "better stuff"; $p3 = "best stuff"; $etc = "!"
$script = [scriptblock]::Create("MyScriptOnRemoteServer.ps1 $p1 $p2 $etc")
#strings get interpolated/expanded while a direct scriptblock does not
# the $parms are now expanded in the script block itself
# ...so just call it:
$result = invoke-command $computer -script $script
Passing arguments was very frustrating, trying various methods, e.g.,
-arguments, $using:p1, etc. and this just worked as desired with no problems.
Since I control the contents and variable expansion of the string which creates the [scriptblock] (or script file) this way, there is no real issue with the "invoke-command" incantation.
(It shouldn't be that hard. :) )
I suspect its a new feature since this post was created - pass parameters to the script block using $Using:var. Then its a simple mater to pass parameters provided the script is already on the machine or in a known network location relative to the machine
Taking the main example it would be:
icm -cn $Env:ComputerName {
C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 -one "uno" -two "dos" -Debug -Clear $Using:Clear
}
I needed something to call scripts with named parameters. We have a policy of not using ordinal positioning of parameters and requiring the parameter name.
My approach is similar to the ones above but gets the content of the script file that you want to call and sends a parameter block containing the parameters and values.
One of the advantages of this is that you can optionally choose which parameters to send to the script file allowing for non-mandatory parameters with defaults.
Assuming there is a script called "MyScript.ps1" in the temporary path that has the following parameter block:
[CmdletBinding(PositionalBinding = $False)]
param
(
[Parameter(Mandatory = $True)] [String] $MyNamedParameter1,
[Parameter(Mandatory = $True)] [String] $MyNamedParameter2,
[Parameter(Mandatory = $False)] [String] $MyNamedParameter3 = "some default value"
)
This is how I would call this script from another script:
$params = #{
MyNamedParameter1 = $SomeValue
MyNamedParameter2 = $SomeOtherValue
}
If ($SomeCondition)
{
$params['MyNamedParameter3'] = $YetAnotherValue
}
$pathToScript = Join-Path -Path $env:Temp -ChildPath MyScript.ps1
$sb = [scriptblock]::create(".{$(Get-Content -Path $pathToScript -Raw)} $(&{
$args
} #params)")
Invoke-Command -ScriptBlock $sb
I have used this in lots of scenarios and it works really well.
One thing that you occasionally need to do is put quotes around the parameter value assignment block. This is always the case when there are spaces in the value.
e.g. This param block is used to call a script that copies various modules into the standard location used by PowerShell C:\Program Files\WindowsPowerShell\Modules which contains a space character.
$params = #{
SourcePath = "$WorkingDirectory\Modules"
DestinationPath = "'$(Join-Path -Path $([System.Environment]::GetFolderPath('ProgramFiles')) -ChildPath 'WindowsPowershell\Modules')'"
}
Hope this helps!
This is an unfortunate situation. Positional parameters work.
# test.ps1
param($myarg1, $myarg2, $myarg3)
"myarg1 $myarg1"
"myarg2 $myarg2"
"myarg3 $myarg3"
# elevated prompt
invoke-command localhost test.ps1 -args 1,$null,3
myarg1 1
myarg2
myarg3 3
Or you can hardcode a default.
# test2.ps1
param($myarg='foo2')
dir $myarg
invoke-command localhost test2.ps1
Cannot find path 'C:\Users\js\Documents\foo2' because it does not exist.
Or copy the script there:
$s = New-PSSession localhost
copy-item test2.ps1 $home\documents -ToSession $s
icm $s { .\test2.ps1 -myarg foo3 }
Cannot find path 'C:\Users\js\Documents\foo3' because it does not exist.