I'm currently working on a PowerShell module, and I've come across something rather unusual that I cannot figure out how to duplicate. I'm using a module from Az PowerShell 3.2.0 as a reference.
I have the following example from Microsoft's Az.Dns Module:
https://learn.microsoft.com/en-us/powershell/module/az.dns/Add-AzDnsRecordConfig
$RecordSet = Get-AzDnsRecordSet -Name www -RecordType A -ResourceGroupName MyResourceGroup -ZoneName myzone.com
Add-AzDnsRecordConfig -RecordSet $RecordSet -Ipv4Address 1.2.3.4
Set-AzDnsRecordSet -RecordSet $RecordSet
The $RecordSet variable is being set locally, passed as a parameter to the Add-AzDnsRecordConfig command of this module, and the value of the $RecordSet local variable is then being automatically updated. When this variable is passed to the Set-AzDnsRecordSet command as a parameter, it contains the updated value it was assigned and not its initial value. Note that there is no additional assignment statement of the return value of Add-AzDnsRecordConfig.
How is this possible?
I know that I can define a function parameter as type [ref] or System.Management.Automation.PSReference and then pass by reference when it is called as function -param ([ref]$myVariable). I can then update the value using $myVariable.Value, but that is not what is happening here. Somehow, this variable is being passed by value, and the value is being updated back in the local scope as if it were passed by reference.
Changing the name of the local variable also does not break this functionality. I've also done a Show-Command -Name Add-AzDnsRecordConfig and I can confirm that the type is not System.Management.Automation.PSReference.
I have a need to duplicate this functionality as closely as possible, as I am building a wrapper of sorts around this, but I am not sure how Microsoft is making this magic happen within this command.
#zett42 Thank you for the concise answer. I definitely over-complicated this, and I did not realize that objects were automatically passed by reference without the need to specify it. As it turns out, I can simply reference the parameter within the function as $RecordSet.Property = "New Value".
Back in the local scope, that does update the initially defined variable.
https://johnfabry.azurewebsites.net/2015/06/26/powershell-reference-types-and-value-types/
This article also helped me to understand how this works.
Related
Are there any rules (or will I run into any problems) if I name the parameters of a function the same as the variable I will pass into them?
For example in Python:
def foo(param):
pass
param = 2
foo(param)
In the fairly limited programming I've done, I have not ran into any problems doing this. Will I get problems in certain languages? Is this okay to do, or is it a practice to be avoided?
The "problem" in this particular case is that the function parameter name will shadow the outer param variable; i.e. you cannot (implicitly) refer to the global param anymore because inside your function param is defined as a local variable.
But, this is really as it should be. Your function should only worry about the parameters it declares locally, not about implicit global variables. Conversely, a caller of a function should not have to worry about anything that goes on inside a function. Naming a variable the same as a parameter to a function is of no consequence to the caller, and should be of no consequence to the function itself.
So, no, there's absolutely no issue here.
I'm trying to transfer parameter from RawRequest using SoapUI but when reading it, value changes.
The parameter is request ID (which is unique for every test), it is requested by every test case from Custom Properties, where it is stored as follows:
${=((System.currentTimeMillis().toString()).subSequence(4, (System.currentTimeMillis().toString()).length())).replaceFirst("0", "")}
Above generates number like this for example:17879164.
The problem starts, when I'm trying to transfer it using either in build in feature or Groovy script. Both read parameter incorrectly:
Following is how the parameter presents in RawRequest window:
This is how it is read in Transfer window in SoapUI:
And finally, how it is read by Groovy script:
Can any one explain, why this value despite being shown in SoapUI RawRequest window as 17879164 is then read as 17879178 using two different methods?
I think the clue might be, that when I'm using "flat number" as reqId and not the generated one, both methods work fine and return correct number. But in this case when it is RawRequest, I understand that it is set once and for all, so what is show in the window and what is being read, should be the same.
What you are seeing is a "feature" in SoapUI. Your transfer step will transfer the code, which will then get evaluated again, resulting in a different value.
What you need to do is:
Create a test case property.
Set the property from test case setup script to a value. So in your case, something like testCase.setPropertyValue("your_property", ((System.currentTimeMillis().toString()).subSequence(4, (System.currentTimeMillis().toString()).length())).replaceFirst("0", ""))
Anywhere in your test refer to the test case property ${#TestCase#your_property}... which is a fixed value at this point, so will be always the same.
I have a namespace variable which is defined as below:
namespace eval ::SMB::{
variable SmbInfo
------
------
proc ::SMB::SmbCreate {name dutport} {
variable SmbInfo
global DutPorts DutPort_2 DutPorts_3 smb
------
------
if{"" != [info command SMB::$name]} {
return -code error "command name \"$name\" already exists"
}
set SmbInfo($name -DutPort) $dutport
I am new to Tcl and trying to understand the above piece of code. Few questions, please correct me if I am wrong at any point:
The variable SmbInfo defined on top in namespace is getting overridden by the one declared in the procedure SmbCreate. I am unable to figure out what is the objective of the line:
set SmbInfo($name -DutPort) $dutport
I can see that 'DutPorts' is defined as global but I could not find 'DutPort'. I have not executed the code yet. Could it be an error?
Is ($name - DutPort) creating an array index for the variable SmbInfo and the value of $dutport is being set to that particular array variable?
I have similar code structures in the file like below
set SmbInfo($name - SmbSetDmac) [BuildMac1 $SmbInfo($from_name-DutPort)]
Where BuildMac1 is a procedure. A bit explanation of the above code might also make the thing clear.
If anything I missed to post in the question, kindly point me, I will edit my question.
Thanks in advance.
The second declaration doesn't override, it's the same variable in both cases.
The command is a syntax error because of the space after $name. The intent seems to be to assign the value of $dutport to the member of SmbInfo that has the name "$name -DutPort" (where $name is replaced by the variable value).
A similar assignment, but here the value comes from the result of the command.
There are a few syntax errors in the code, too many or too few spaces here and there. It seems unlikely this code has ever been executed.
The purpose of the smb::SmbCreate command would seem to be to 1) create a new command in the SMB namespace named by the first parameter (unless such a command already exists) and 2) store metadata in the SmbInfo namespace variable, indexed by a) the name parameter and b) a keyword such as -DutPort or -SmbSetDmac.
Code like this essentially implements an ad-hoc object-oriented interface. If the whitespace issues are resolved, it should work fine.
You have many syntactic problems that are going to cause you much grief. Tcl cares very much about its syntax level, which includes exactly where the spaces and newlines are, and whether there are {braces} and [brackets] as expected. You must get these things right.
Looking at the specific code you're having problems with, this line:
set SmbInfo($name -DutPort) $dutport
would appear to be highly unlikely, as it is passing three arguments to the set command when that only takes one or two. I'd guess that you've got a command that you're calling to obtain a key for an array, and that the code therefore ought to be this:
set SmbInfo([$name -DutPort]) $dutport
See those [brackets]? They matter here, as they say “run my contents as a little subscript and use the result”. With that sorted out, there's also the question of whether $name -DutPort works at all, but you'll just have to be guided by the error messages there. Tcl usually gives very good error messages, though sometimes you have to think about why the code got in the state where it is giving that message in order to figure out what the actual problem is. You know, usual debugging…
I would expect similar problems with:
set SmbInfo($name - SmbSetDmac) [BuildMac1 $SmbInfo($from_name-DutPort)]
and would guess that it is actually supposed to be:
set SmbInfo([$name -SmbSetDmac]) [BuildMac1 $SmbInfo([$from_name -DutPort])]
Note again that I have modified the spaces to follow the existing pattern (which I'm guessing is a property access; it looks like it's OTcl or XOTcl) and added brackets.
Finally, this line:
if{"" != [info command SMB::$name]} {
is also syntactically wrong, and should instead be:
if {"" != [info command SMB::$name]} {
That extra space matters, because it separates the word that is the command name (if) from the word that is the condition expression. The remainder of the line is probably correct (the SMB::$name might be suspicious, except you're using it in info command, but then you probably only need info command $name as it already knows about what namespace you're working in and you're using the unqualified name elsewhere).
This is driving me potty.
I'm trying to pass two SSIS variables to a command line executable using an Execute Process Task object.
No matter what I try, the values are not being passed through.
This is how it is set currently:
The variables are in scope and are of type string (representing integer values).
Sods law came into effect after posting this question. I tried evaluating my variables as an expression and assigning the resulting string to the arguments property.
I don't see why this would work over the example I gave, but it does, so I'm using that.
This is what I'm trying to do in a script task:
long lngMaxRowsToPull = Convert.ToInt64(Dts.Variables["Project::MaxRowsPerPull"].Value);
I get an error message that the variable does not exist.
Yet Its defined as a ReadOnlyVariable to the script and it does exist as a project parameter.
So close. ;)
Your code is trying to access a variable/parameter named Project::MaxRowsPerPull
In fact, the $ is significant so you need to reference $Project::MaxRowsPerPull
Also note that you have the data type for the parameter as Int32 but are then pushing it into Int64. You can always put a smaller type into a larger container but if you tried to fill the parameter with too large a value your package will asplode.
You need to add $ to your parameter fetch name as per syntax.
long lngMaxRowsToPull = Convert.ToInt64(Dts.Variables["$Project::MaxRowsPerPull"].Value);