Author Posts

August 13, 2013 at 5:46 am

So I have a function that I am building to get inventory information from various computers on our network. One of the parameters for this is Credential.

I am doing four WMI queries (so far) to grab os, bios, system, disk information. I am thinking there has to be a better, cleaner way to do it than go:

if($credential)
{
# run all wmi queries with credential
}
else
}
# run all wmi queries without credentials
}

What is this better way?

Thanks
sb

August 13, 2013 at 6:00 am

I don't know if it's "better," but you can certainly do:

if ($PSBoundParameters.ContainsKey('credential')) {
 # you have one
} else {
 # you don't
}

August 13, 2013 at 6:55 am

There is a better way. 🙂

When you declare your Credential parameter, declare it like this:

[Parameter()]
[ValidateNotNull()]
[System.Management.Automation.PSCredential]
[System.Management.Automation.Credential()]
$Credential = [System.Management.Automation.PSCredential]::Empty

Now you can simply pass the $Credential value through to the Credential parameter of your Get-WmiObject calls, because it will have a default value that is supported by Get-WmiObject, so if credentials are not required it will still work. For example:

# This works even if the caller of our function didn't pass credentials
Get-WmiObject Win32_Service -Credential $Credential

Even better, by defining it this way you can pass in a Credential object or a string into your command, just like Get-Credential, and you'll be prompted if you pass in a string for the password.

Caveat: Some cmdlets that accept a Credential parameter do not support/check for [System.Management.Automation.PSCredential]::Empty like they should. This should be treated as a bug by those cmdlet authors. There is a workaround though, and that is to use splatting. For example, if you want a solution that works for any cmdlet, you could do the following.

1. In the top of your function, add this logic:

$credSplat = @{}
if ($Credential -ne [System.Management.Automation.PSCredential]::Empty) {
    $credSplat['Credential'] = $Credential
}

2. Now wherever you want to optionally pass in the Credential parameter, you just do this:

Get-WmiObject Win32_Service @credSplat

If no credentials are passed in, or if the Empty credential object is passed in (or if it is left as default), then you don't pass anything to Get-WmiObject because $credSplat will be an empty hash table. Otherwise, if you have credentials, they go through because $credSplat will contain the credential value. Splatting is an awesome feature made for this very purpose.

February 3, 2014 at 6:31 pm

I am trying to do this for a function that also collects inventory from systems. I've tried adding the code above but I am not doing something right as the function won't run once I add this in. I did find another cool function in part of another script, if I could add that in it would be great. There are a few functions in the script that I've found would be good. There's 1 that prompts what type of input you want to run the function against – a file, 1 name, search the domain, then 1 that prompts if you want to specify a different credential.
Can anyone help me figure out what to add to the function I want? The function is straight forward as it's doing cmdlet binding

Here's the start of the function I'm trying to use
[CmdletBinding()]
PARAM(
[Parameter(ValueFromPipeline=$true)]
[String[]]$ComputerName = $Computers,
[String]$Errors = ".\Failures.log"
)
BEGIN {}#PROCESS BEGIN
PROCESS{
FOREACH ($Computer in $ComputerName) {

February 3, 2014 at 6:31 pm

I am trying to do this for a function that also collects inventory from systems. I've tried adding the code above but I am not doing something right as the function won't run once I add this in. I did find another cool function in part of another script, if I could add that in it would be great. There are a few functions in the script that I've found would be good. There's 1 that prompts what type of input you want to run the function against – a file, 1 name, search the domain, then 1 that prompts if you want to specify a different credential.
Can anyone help me figure out what to add to the function I want? The function is straight forward as it's doing cmdlet binding

Here's the start of the function I'm trying to use
[CmdletBinding()]
PARAM(
[Parameter(ValueFromPipeline=$true)]
[String[]]$ComputerName = $Computers,
[String]$Errors = ".\Failures.log"
)
BEGIN {}#PROCESS BEGIN
PROCESS{
FOREACH ($Computer in $ComputerName) {