Can an array variable defined in Azure DevOps "variable group" - azure

I want to define some variables in Azure devops "variable group" which will be used in Powershell, but when the variable type is string it works, but some is array or object went wrong. mine look like below. left is the name,right is the value
vmAlertedArray_backup => #("wbubuntu","wbubuntu2")
1.when in azure devops script I use, it went wrong
$vmAlertedArray_backup = $env:vmAlertedArray_backup
foreach($c in $vmAlertedArray_backup){
Write-Host "$c"
}
2.below in powershell in local works
$vmAlertedArray_backup = #("wbubuntu","wbubuntu2")
foreach($c in $vmAlertedArray_backup){
Write-Host "$c"
}
Can any one show some experience about this? thanks

It is suggested to only pass variables as string. If you want to pass an object to other tasks, you can use "ConvertTo-Json -Compress" to convert it to a json string.
$objectString = $object | ConvertTo-Json -Compress
Write-Host "##vso[task.setvariable variable=objectString;]$objectString"
And in the next PS task, you can pass it as environment variable. But, please enclose the variables in single quotes.
And then you can use "ConvertFrom-Json" to convert the string to an object.
$getFromEnv = $env:objectString | ConvertFrom-Json
foreach( $obj in $getFromEnv){
Write-Host ("displayName:{0} Id:{1}" -f $obj.displayName, $obj.Id)
}

I just pass the variable in as a string and then split it to create an array in PowerShell
Variable = Prod1,Prod2,Prod3
$array = $variable.Split(',)
If need be you can add a Trim to the end in case there are spaces
Variable = Prod1,Prod2 ,Prod3
$array = $workspaces.Split(',').trim()

Related

powershell psobject showing as string instead of psobject, how to convert back to psobject

I have the following variable $Obj set to the following string value:
$Obj = '#{Version=1; Name=a;}'
How do I convert this value from a string into a custom psobject?
I would like to be able to call
$Obj.Version and get the value 1. Currently this call returns nothing.
Note: Due to how I am retrieving this variable, I can't initialize it without the single quotes.
Edit:
Here is the current code:
$Command = "script.ps1 -ExtraInfo $_"
Write-Host $Command
Invoke-Expression -Command $Command
where $_ is #{Version=1; Name=a;} (without the quote)
Originally this code was written as
. script.ps1 -ExtraInfo $_
and worked, but when I added unit tests I changed it to use Invoke-Expression so that it could be testable with Pester unit tests. Is there a better way?
Edit2:
Turns out this can be solved by putting a back tic ` before the expression and that solves the issue for me. Thank you everyone for your input.
$Command = "script.ps1 -ExtraInfo `$_"
Write-Host $Command
Invoke-Expression -Command $Command
The stringified version of a [pscustomobject] instance, which resembles a hashtable literal, is not suitable for programmatic processing, as the following example demonstrates:
# Stringify a [pscustomobject] instance.
PS> "$([pscsutomobject] #{ Version=1; Name='a value' })"
#{Version=1; Name=a value} # !! Quoting of the .Name value was lost
The problem gets worse for property values that are themselves complex objects.
Since you do appear to have access to the original [pscustomobject] instance, the solution is not to stringify.
For that, you simply need to avoid up-front string interpolation by using a verbatim (single-quoted) string literal ('...') and letting Invoke-Expression - which should generally be avoided - interpret the $_ variable as its original type:
# Use *single* quotes to prevent up-front expansion.
$Command = 'script.ps1 -ExtraInfo $_'
Write-Host $Command
Invoke-Expression -Command $Command
Note that the use of a verbatim (non-interpolating) string literal makes the use of Invoke-Expression safe here, though, as Santiago Squarzon points out, there may be a better alternatives in general, and particularly in the context of Pester.
A script-block-based solution ({ ... }) that receives the object as an argument:
$Command = { script.ps1 -ExtraInfo $args[0] }
Write-Host "Calling { $Command } with argument $_"
. $Command $_
This doesn't work with Name=a because a is not a known object (or at least not defined in my PS Session). But if this is a string, this can be done with the following script:
$Obj = '#{Version=1; Name="a";}'
$s= [System.Management.Automation.ScriptBlock]::Create("New-Object -TypeName PSObject -Property $Obj")
$o = Invoke-Command -ScriptBlock $s
$o.Version
As I stated in my comment, this is odd, and should be resolved earlier in the code base. However, if that is not possible, use Invoke-Expression
like so
$newObj = Invoke-Expression $Obj
Further reading on Invoke-Expression

Azure adds leading space to variable

If I run this powershell code locally:
$url = "refs/pull/5625/merge"
$SourceBranchFromBuild = $url.split('/')[-1]
$featureReleaseUrl = "http://$sourceBranchFromBuild.azurewebsites.net"
Write-Output $featureReleaseUrl
The output is:
http://merge.azurewebsites.net
When I run this code on a Azure Powershell:
$url = "refs/pull/5625/merge"
$SourceBranchFromBuild = $url.split('/')[-1]
Write-Host "##vso[task.setvariable variable=prSourceBranchName;]"$SourceBranchFromBuild
And then create the URL in another Azure Powershell script:
$featureReleaseUrl = "http://$env:prSourceBranchName.azurewebsites.net"
Write-Output $featureReleaseUrl
The ouput is
http:// merge.azurewebsites.net
What's causing this leading space character in the $env:prSourceBranchName?
Azure isn't adding anything - your write-host is!
Your code is doing this:
PS> $x = "xxx"
PS> write-host "aaa"$x
aaa xxx
but presumably you want
PS> $x = "xxx"
PS> write-host "aaa$x"
aaaxxx
Note where the second quote is the write-host in both examples. In the first it's before the $x variable name. In the second it's after.
In your question it's calling this (with the quote before the variable name):
Write-Host "##vso[task.setvariable variable=prSourceBranchName;]"$SourceBranchFromBuild
which will write a logging command to the log file, and Azure DevOps will process that and update the environment variable.
You're probably expecting it to write this to the log file:
##vso[task.setvariable variable=prSourceBranchName;]merge
but it's actually writing this:
##vso[task.setvariable variable=prSourceBranchName;] merge
Try switching your code to this (i.e. second quote after the variable name):
Write-Host "##vso[task.setvariable variable=prSourceBranchName;]$SourceBranchFromBuild"
and it should omit the space in front of the branch name in your url.
#PeterBoomsma Try putting $SourceBranchFromBuild inside the double quotes like this:
Write-Host "##vso[task.setvariable variable=prSourceBranchName;]$SourceBranchFromBuild"

Variable name is content of another variable

I have a list of variables:
$desa = "filtering regex for desa"
$cdo = "different regex for cdo"
etc.
Now, I have a loop:
Foreach ($profilename in ("desa", "cdo")) {
# filter out data from $profilename file where regex is contained in
# variable named after the content of $profilename
}
So, in other words, I need to use a string contained in one of the variables at the top, and the name of that variable is the exact content of the $profilename variable.
Can PowerShell do this?
Might be easier to us a hash table of regexes than separate variables for each one:
$filters = #{
desa = "filtering regex for desa"
cdo = "different regex for cdo"
}
Foreach ($profilename in
( "desa", "cdo")
)
{
(Get-content <profilename file>) -match $filters[$profilename]
}
Just name the keys after your profile names.
As #mjolinor said: hashtables are a better approach for this. However, if for some reason you must expand a "constructed" variable you can do it by using the $ExecutionContext automatic variable:
PS C:\> $a = 'foo'
PS C:\> $b = 'a'
PS C:\> $c = "`$$b"
PS C:\> $c
$a
PS C:\> $ExecutionContext.InvokeCommand.ExpandString($c)
foo
Applied to your code that might look like this:
$desa = "filtering regex for desa"
$cdo = "different regex for cdo"
foreach ($profilename in 'desa','cdo') {
$pattern = $ExecutionContext.InvokeCommand.ExpandString("`$$profilename")
$something | ? { $_ -match $pattern } | ...
}

Computername and string search

Having some string trouble, I can get the computer name using $env:computerName and it returns something like ABC1211. I am guessing that the ABC1211 is an object and I want to do a search. I want to search this for the characters ABC and then I need to do some other things with certs. I am having problem searching for the ABC.
I tried:
[string[]]$test = $env:computerName
to turn it into a string and then do a search within $test by:
if ($test.contains(("DEF")) {
Write-Host "Yeah"
}
else {
Write-Host "NO"
}
but its not working. Am I missing something? I am guessing this is really simple, but I'm just not getting it.
$env:computerName is already a string. There is no need to cast it to [string[]]. Just call the .contains method on the variable directly:
if ($env:computerName.contains("ABC")) {
Write-Host "Yeah"
}
else {
Write-Host "NO"
}
Incidentally, casting a variable to [string[]] makes an array of strings, not a single string:
PS > [string[]]$test = $env:computerName
PS > $test.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String[] System.Array
PS >
So, $test was actually of the form ($env:computerName,) and you were using Array.Contains instead of String.Contains.
To cast to a string, you would use just [string]:
[string]$test = $env:computerName
But as I said above, this is unnecessary since $env:computerName is already a string.
Ok I figured it out...was a lot more simple than I thought. Here's the answer: -match
I just had to use that instead of .contains or -like also I don't need to change the object into a string.

Powershell object as parameter

i got some problem while preparing some useful script based on PS.
I try to make script which will collect data from Active Directory and Exchange (users/mailboxes), then this data will be processed in further part of script (in some function for example)
function toProcess($userObj, $mailboxObj)
{
echo $userObj.enabled #the output is null
}
$users = get-adusers -Filter * -properties *
foreach($user in $users)
{
$guid = $user.objectGuid.toString()
if($user.mail -ne $null)
{
$mailbox = get-mailbox $guid | select-object *
if($mailbox -ne $null)
{
toProcess($user, $mailbox)
}
}
}
When there is assigned only one parameter ($user) to the onProcess(), function executes correctly and display status of account. When i assign two objects, values becomes null.
What's wrong?
I use powershell 2.0
When calling PowerShell functions, arguments are separated by spaces, and parentheses are not needed.
Your function call should look like this.
toProcess $user $mailbox
By placing a comma between the variables, you were creating a single argument that is an array of objects.

Resources