Powershell function Params getting unexpected values when CSV fields are not present - powershell

I am writing a PowerShell function which can take pipeline input. Specifically I am testing it with Import-CSV. Many of the params are not mandatory, which means sometimes the CSV will not have those columns. For boolean values this is working as expected, but with string values, a missing CSV field yields a copy of the row object in the string field.
Here is an example problem parameter:
[Parameter(Mandatory=$False,
ValueFromPipeline=$True,
ValueFromPipelinebyPropertyName=$True,
HelpMessage="TCP Port of the remote server")]
[Alias('Port', 'Remote Server Port')]
[string]$RemoteServerPort = "5500",
Now, if the field is missing, I would expect the value to be "5500" as specified, but instead I get:
$RemoteServerPort = #{Name=KG; IP=10.1.1.1; Username=Admin; Password=}
I've done some looking around, but frankly I'm not even sure what to search for.

This is because you specified ValueFromPipeline=$True so that PoSh coerces the piped object to a string if it cannot bind the parameter by property name. You could solve that by removing ValueFromPipeline=$True from this parameter and introduce another one to be bound to the piped object, i.e. something like this
function MyTestFunc() {
param(
[Parameter(ValueFromPipeline=$True)]
[object]$PipedObj,
[Parameter(Mandatory=$False,
ValueFromPipelinebyPropertyName=$True,
HelpMessage="TCP Port of the remote server")]
[Alias('Port', 'Remote Server Port')]
[string]$RemoteServerPort = "5500"
)
Write-Host "Port: $RemoteServerPort / Obj: $PipedObj"
}
$o1 = [pscustomobject]#{"Server" = "123"; "Port" = "12345"}
$o2 = [pscustomobject]#{"Server" = "1234"; "OS" = "Win3.1"}
$o1 | MyTestFunc
$o2 | MyTestFunc
Will result in
Port: 12345 / Obj: #{Server=123; Port=12345}
Port: 5500 / Obj: #{Server=1234; OS=Win3.1}
A way to see in detail what is actually happening behind the scenes is to use Trace-Command like so
Trace-Command ParameterBinding {$o2 | MyTestFunc} -PSHost

Related

PowerShell Active Directory list all Multi-Valued attributes

not sure if I'm chaing the wild goose here but as per subject I'd need to get a list of AD attributes, for the user ObjectClass, that are multie valued.
For example the proxyAddresses exchange specific attribute is multi valued where extensionAttribute* only accept a single string.
We use a heavily customized schema and while I could go through each attribute documentation I'd rather get a list of aforementioned attributes via PowerShell.
I've tried using ldp.exe but could not achive desired results and was wondering if there is a way to do this via PowerShell or .Net managed code.
Thanks in advance for any help/pointer.
So you have to query the Schema part of the directory and look for objectClass attributeSchema and attribute isSingleValued (FALSE). The part of the distinguichName wichh is invariant is : CN=Schema,CN=Configuration.
try first with CSV :
csvde -f MultivaluedAttributes.csv -d CN=Schema,CN=Configuration,DC=MySubdomain,DC=MyDomain,DC=com -r "(&(objectclass=attributeSchema)(isSingleValued=FALSE))" -l lDAPDisplayName
Here is the powershell code.
# LDAPSchemaQuery.PS1
try
{
$dn = New-Object System.DirectoryServices.DirectoryEntry ("LDAP://179.22.21.01/CN=Schema,CN=Configuration,DC=MyDomain,DC=MyExt","MyUser", 'MyPassword')
# Query into the Schema
# csvde -f MultivaluedAttributes.csv -d CN=Schema,CN=Configuration,DC=office,DC=coyotesystems,DC=com -r "(&(objectclass=attributeSchema)(isSingleValued=FALSE))" -l lDAPDisplayName
$Rech = new-object System.DirectoryServices.DirectorySearcher($dn)
#$Rech.filter = "(&(objectclass=user)(mail=*)(!(UserAccountControl:1.2.840.113556.1.4.803:=2)))"
$Rech.filter = "(&(objectclass=attributeSchema)(isSingleValued=FALSE))"
$Rech.SearchScope = "subtree"
$dumy=$Rech.PropertiesToLoad.Add("lDAPDisplayName")
$adAttributes = $Rech.findall()
foreach ($adAttribute in $adAttributes)
{
$multivaluedAttribute = try{$adAttribute.Properties["lDAPDisplayName"]}catch{""}
$multivaluedAttribute
}
}
catch
{
Write-Verbose "LDAPSchemaQuery : PB with $($adAttribute.Path)"
}

How to add a numeric switch to a PowerShell script

I know how to add switch parameters to PowerShell scripts, but the name of the switch is always a (valid) identifier like -Enable because the name is generated from the backing PowerShell variable.
[CmdletBinding()]
param(
[switch] $Enable = $false
)
Some tools have switches like -2008. Normally, one would name the switch $2008 but this is not a valid identifier.
How can I implement such a switch as a boolean value in PowerShell?
Or in other words: How to specify a different parameter name then the backing variable?
Edit 1
I wasn't aware of number only variables (which is very strange for a programming language...). Anyhow, I created that example:
function foo
{ [CmdletBinding()]
param(
[switch] $2008
)
Write-Host "2008=$2008"
}
For this code, which is accepted as valid PowerShell, I get a auto completion as wanted. But when providing that parameter, I get this error message:
foo : Es wurde kein Positionsparameter gefunden, der das Argument "-2008" akzeptiert.
In Zeile:1 Zeichen:1
+ foo -2008
+ ~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [foo], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,foo
Translation: No positional parameter was found, that accepts the argument "-2008".
The purpose of the script is to provide translations / wrappers for command line interfaces.
Here is a set of standardized executables with parameters:
vcom.exe -2008 design.vhdl
vsim.exe -2008 design
Translation:
ghdl.exe -a --std=2008 design.vhdl
ghdl.exe -e --std=2008 design
ghdl.exe -r --std=2008 design
I would like to keep the feature of auto completion for parameters, otherwise I could process all remaining parameters and translate them by hand.
PowerShell doesn't support numeric parameters (See this answer).
Could a validateset be an acceptable solution to your problem ?
Validate set does benefit from the autocompletion feature and this is the next best thing, in my opinion, of what you wanted.
Foo & Foos — both are the same, except Foos accept multiple parameters.
foo -std 2008
foos -std 2008,2009,2010
function foo
{ [CmdletBinding()]
param(
[ValidateSet("2008",
"2009",
"2010",
"2011","2012")][INT]$std
)
Write-Host "std:$std"
}
function foos
{ [CmdletBinding()]
param(
[ValidateSet("2008",
"2009",
"2010",
"2011","2012")][INT[]]$std
)
$std | foreach {Write-Host "std: $_"}
}
foo -std 2008
foos -std 2008,2009,2010

How do I use a secret variable in a vsts release task?

I've got a release definition in vsts that needs access to a password I've defined as a secret variable in a variable group. I've linked that group to this release definition but when I run the task the parameter ends up blank. Is there anything special I need to do to get the value of a secret variable?
Definition of the powershell task that uses the password
Linked variable group
Error output:
2017-08-09T14:01:17.9262375Z ##[command]. 'C:\agent_work\r1\a\$(AGENT.BUILDDIRECTORY)\RCV\deploys\common\Get-FromArtifactory.ps1' -repoUsername developer -repoPassword -repoPath libs-snapshot-local
2017-08-09T14:01:18.8168538Z ##[error]C:\agent_work\r1\a\$(AGENT.BUILDDIRECTORY)\RCV\deploys\common\Get-FromArtifactory.ps1 : Missing an argument for parameter 'repoPassword'. Specify a parameter of type 'System.String' and try again.
Edited to add more info as requested.
This is the start of my Get-FromArtifactory.ps1
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[String]
$repoUsername,
[Parameter()]
[String]
$repoPassword,
# Other params
)
#setup credentials object for arty access
$secPassword = $repoPassword | ConvertTo-SecureString -asPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($repoUsername, $secPassword)
Edit 15/08/2017 - I've updated it to use quotes as suggested by #Marina-MSFT but it's still just passing in blank.
Amended script to print out part of password:
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[String]
$repoUsername,
[Parameter()]
[String]
$repoPassword,
#other params
)
write-host "pword $repoPassword"
write-host "1st char: $($repoPassword[0])"
2017-08-15T09:23:00.8606081Z ##[command]. 'C:\agent_work\r1\a\RCV\deploys\common\Get-FromArtifactory.ps1' -repoUsername developer -repoPassword "" -repoPath libs-snapshot-local -artifactName ipo-deposit-accounts_2.11 -artifactPath uk/gov/ipo -artifactVersion 0.1-SNAPSHOT -downloadDir C:\agent_work\r1\a
2017-08-15T09:23:02.3606174Z pword
2017-08-15T09:23:02.3606174Z 1st char:
Same with single quotes
2017-08-15T09:22:10.6573655Z ##[command]. 'C:\agent_work\r1\a\RCV\deploys\common\Get-FromArtifactory.ps1' -repoUsername developer -repoPassword '' -repoPath libs-snapshot-local -artifactName ipo-deposit-accounts_2.11 -artifactPath uk/gov/ipo -artifactVersion 0.1-SNAPSHOT -downloadDir C:\agent_work\r1\a
2017-08-15T09:22:11.2198723Z pword
2017-08-15T09:22:11.3761178Z 1st char:
I've got it working now, there were 2 things going on.
Having . in the name of a secret variable in a variable group
doesn't work. I recreated this issue in a separate release
definition/variable group.
Even after I removed the . in my var
names I still had to recreate the variable group for it to work.
Bug for issue with . in variable name raised here: https://developercommunity.visualstudio.com/content/problem/94475/secret-variable-in-variable-not-group-not-availabl.html

PowerShell - InvalidCastException when returning Boolean to explicitly declared variable [duplicate]

This question already has answers here:
Function return value in PowerShell
(10 answers)
Closed 5 years ago.
I've written a PowerShell script to perform some pre-installation setup for a series of patches I'm deploying to client computers across our estate and I'm hitting a bit of an odd issue that I can't wrap my head around.
The setup patch checks the 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe.config' file due to a "feature" of PowerShell 2.0 whereby the application uses .NET Framework 2.0.0 by default instead of 4.5.2, preventing certain functions from being executed. If the file doesn't exist or the evaluated values don't match a specification, I add the XML file and provide the necessary values.
The command I run is as follows:
$psConfigDir = "C:\Windows\System32\WindowsPowerShell\v1.0"
$psConfigFileName = "powershell.exe.config"
[boolean]$psExeXml = Set-PSRuntimeConfigs -FilePath ( [String]::Format("{0}\{1}", $psConfigDir, $psConfigFileName) ) -CLRVersions #("v4.0.30319", "v2.0.50727")
...and the Set-PSRuntimeConfigs method is found in a PowerShell Module I created with the code below:
Function Set-PSRuntimeConfigs {
[CmdletBinding()]
Param(
[String]$FilePath,
[System.Collections.ArrayList]$CLRVersions
)
Try {
$xmlWriter = New-Object System.Xml.XmlTextWriter($FilePath, $null)
$xmlWriter.Formatting = "Indented"
$xmlWriter.Indentation = 4
$xmlWriter.WriteStartDocument()
$xmlWriter.WriteStartElement("configuration")
$xmlWriter.WriteStartElement("startup")
$xmlWriter.WriteAttributeString("useLegacyV2RuntimeActivationPolicy", $true)
$CLRVersions | ForEach-Object {
$xmlWriter.WriteStartElement("supportedRuntime")
$xmlWriter.WriteAttributeString("version", $_)
$xmlWriter.WriteEndElement()
}
$xmlWriter.WriteEndElement()
$xmlWriter.WriteEndElement()
$xmlWriter.WriteEndDocument()
$xmlWriter.Close()
$xmlWriter.Dispose()
return $true
} Catch {
echo "ERROR: Exception occurred during XML write process!"
echo "ERROR: Exception message: $($_.Exception.Message)"
return $false
}
}
However, the function is returning an InvalidCastException when trying to assign the result of the function to the $psExeXml variable. Oddly, PowerShell returns with an error stating that [System.Object()] cannot be converted to type [Boolean] despite the fact that only $true or $false is returned from the function.
My first thought is that an exception was being thrown by the function due to a code issue but the function is written to report the error in the prompt and just return $false in that case... Regardless, I'm stuck and can't figure out where to proceed with this...
If the function produces any output then the result will be an array containing the strings that were output and then the final element will be your boolean.
So for this code:
echo "ERROR: Exception occurred during XML write process!"
echo "ERROR: Exception message: $($_.Exception.Message)"
return $false
the function returns an array of two strings and a boolean.

Powershell argument validation issues

I'm calling a powershell script like so, from within another script.
function test_execute_sql_2_direct_query()
{
& C:\Server\Scripts\PowerShellDeploy\Execute-SQL-Command.ps1 -SERVER_NAME "myserver" -SQL_COMMAND_TYPE "input" -SQL_FILE ".\select.sql" -USER_NAME "username" -PASSWORD "password" -DATABASE "accounts"
}
When I call that function I get an error message from Powershell that says 'Cannot validate argument on parameter 'Query'. The argument is null or empty....'
I don't quite follow why I'm getting that message? The Execute-SQL-Command script doesn't have an argument called 'Query'. Quite possible I'm missing something.
Here's its paramenter section:
param(
[Parameter(
HelpMessage="Server Name")]
[string]$SERVER_NAME = "",
[Parameter(
HelpMessage="Database")]
[string]$DATABASE = "",
[Parameter(
HelpMessage="Path to .SQL File to run. Used in input file mode (not direct query mode)")]
[string]$SQL_FILE ="",
[Parameter(
HelpMessage="Server Port (default = 1433)")]
[string]$SERVER_PORT = "1433",
[Parameter(
HelpMessage="Server Transport (default = tcp")]
[string]$TRANSPORT = "tcp",
[Parameter(
HelpMessage="Method of connecting to database <passthrough, credentialed>")]
[string]$CONNECT_METHOD = "passthrough",
[Parameter(
HelpMessage="Username -- used only for credentialed login")]
[string]$USER_NAME = "username",
[Parameter(
HelpMessage="Command type-- direct query or input file (.sql)")]
[string]$SQL_COMMAND_TYPE = "DIRECT_QUERY",
[Parameter(
HelpMessage="SQL statement text type-- used in direct queries")]
[string]$SQL_STATEMENT = "",
[Parameter(
HelpMessage="Password -- used only for credentialed login")]
[string]$PASSWORD = "pwd")
This one is chalked up to user error-- the actual error was coming from within a line called in Execute-SQL-Command.ps1-- specifically, the Invoke-Sqlcmd cmdlet.