So, i think that I am going crazy and hoping someone can point out my flaw. If you review the function below I am expecting to be able to pass a string value of domain\username to the Credential parameter function and have that convert the string into a PSCredential object similar to MS AD cmdlets. However that’s not the case and I receive the conversion error listed. My expectations are set by this article on TechNet that states the following:
(i)If a parameter accepts a PSCredential object, Windows PowerShell supports several types of input, such as the following:(/i)
(b)Empty (/b)If you supply no input to a mandatory –credential parameter, Windows PowerShell prompts you for the user name and password.
(b)String (/b)If you supply a string to the –credential parameter, Windows PowerShell treats it as a user name and prompts you for the password.
(b)Credential(/b) If you supply a credential object to the –credential parameter, Windows PowerShell accepts it as is.
(b)Keep in mind I haven’t actually finished the cmdlet but it should at least run as written with the correct input and switches.(/b)
Function Set-DNSServers{
[cmdletbinding(SupportsShouldProcess=$true)]
PARAM(
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string[]]$Computers,
[Parameter(Mandatory=$true)]
[System.Management.Automation.PSCredential]$Credential
)
foreach($host in $computers){
write-verbose "Gathering network adapters on $host"
# get network adapaters from WMI
$nics = Get-WmiObject -Class Win32_NetworkAdapterConfiguration -ComputerName $Computers -Credential $Credential | Select-Object -Property PSComputerName,DNSHostname,Description,IPAddress,IPEnabled,DNSServerSearchOrder
# if verbose is enabled output your findings
if($PSCmdlet.MyInvocation.BoundParameters['Verbose']){
write-verbose "Found the following network adapters on $host"
write-verbose ($nics | FT -AutoSize | Out-String)
} # End IF
} # end For $host/$computers
} # End Function
Set-DNSServers -Computers -Credential -Verbose -WhatIf
Set-DNSServers : Cannot process argument transformation on parameter 'Credential'. Cannot convert the value of type "System.String" to type "System.Management.Automation.PSCredential".
At C:\jbtemp\PS\Scripts\Systems\Set-DNSServers.ps1:24 char:52
+ Set-DNSServers -Computers -Credential -Verbose -WhatIf
+ ~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Set-DNSServers], ParameterBindingArgumentTransformationException
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,Set-DNSServers
Note: The order seems to be important. In my testing, if I put the [CredentialAttribute()] before the [PSCredential] type literal, I would still get the same errors you reported. If the CredentialAttribute() was placed after everythign else, then it started to allow strings to be passed in. This may be a bug in PowerShell; I don’t think the order of attributes should matter, but it’s something to be aware of for now.
Also, if you want, you can omit the word Attribute: [System.Management.Automation.Credential()] works fine as well.
I ran this command to see how the cmdlets were doing it:
Trace-Command ParameterBinding -PSHost { Get-Credential 'domain\user' }
# Got this output (among other things):
# DEBUG: ParameterBinding Information: 0 : BIND NAMED cmd line args [Get-Credential]
# DEBUG: ParameterBinding Information: 0 : BIND POSITIONAL cmd line args [Get-Credential]
# DEBUG: ParameterBinding Information: 0 : BIND arg [domain\user] to parameter [Credential]
# DEBUG: ParameterBinding Information: 0 : Executing DATA GENERATION metadata:
# [System.Management.Automation.CredentialAttribute]
That clued me into the CredentialAttribute class, which I think I may have heard about before, but had forgotten. Then I just wrote a couple of test functions using that attribute in my param block to see how it worked (and came across that odd “order matters” situation, which is apparently fixed in the PowerShell v5 preview.)