PowerShell Parameter Sets and Defaults

I was working on a script to copy a single file to multiple destinations, and I needed to specify multiple credentials (for the source and the destination, perhaps they’re different).  Of course, they could be the same.  In either case, I didn’t want to specify extra parameters if I could avoid it.

So, with that in mind, I wanted to do the following:

  • If the credentials are the same for the source and destination, pass a single credential via the -Credential option
  • If the credentials are different, pass -SourceCredential and -DestinationCredential options

That’s easy enough, but the neat trick that I found was that parameter sets will still allow you to set defaults even if you aren’t using them.  For example:

[Parameter(ParameterSetName = "SingleCredential", Mandatory = $true)][PSCredential]$Credential,
[Parameter(ParameterSetName = "DualCredential", Mandatory = $true)][PSCredential]$SourceCredential = $Credential,
[Parameter(ParameterSetName = "DualCredential", Mandatory = $true)][PSCredential]$DestinationCredential = $Credential

So, with this in the Param() block, the following happens:

  • If you pass the -Credential parameter, you can refer to $SourceCredential and $DestinationCredential later in the script – both will have the same credential assigned to them.
  • If you try to pass only one of -SourceCredential or -DestinationCredential, you will be prompted for the option you forgot, like you’d expect (since they’re both required).

It might not seem like much, but it’s a slick little way of handling a unique situation that I ran into.

Update Scheduled Task Password with PowerShell

If you run any scheduled tasks in Windows that rely on an account that must change passwords regularly (which, frankly, every account should at least yearly…), it’s convenient to update the passwords in the least obnoxious way possible.

I’ve recently had reason to perform this particular task, and after updating 8 scheduled tasks across 7 servers via the GUI, I knew there had to be a better way.  And, as always, that better way is with PowerShell.  This appears to be only viable for Windows 10 and Windows Server 2016, but if you’re not using those…please get moving.  It’s 2018, Server 2019 has reached GA, and it’s time to upgrade or replace your old servers.  Yes, 2012 R2 is old.  Get over it.

$TaskCredential = Get-Credential
Get-ScheduledTask | Where-Object { $_.Principal.UserId -eq $TaskCredential.UserName } | Set-ScheduledTask -User $TaskCredential.UserName -Password $TaskCredential.GetNetworkCredential().Password

Simple as that – any scheduled tasks that are being run as the account provided will have their password updated to the new password.  Easy peasy.  But…this requires that you are running the command on the system you want to update?  What about running it remotely?  I’m glad you asked…

Param(
  [Parameter(Mandatory=$true,ValueFromPipeline=$true)][string[]]$ComputerName,
  [Parameter(Mandatory=$true)][PSCredential]$Credential,
  [Parameter(Mandatory=$true)][PSCredential]$TaskCredential
)

Invoke-Command -ComputerName $ComputerName -Credential $Credential -ScriptBlock { Get-ScheduledTask | Where-Object { $_.Principal.UserId -eq ($using:TaskCredential).UserName.Split('\')[1] } | Set-ScheduledTask -User ($using:TaskCredential).UserName -Password ($using:TaskCredential).GetNetworkCredential().Password }

With a little bit of coaxing, you can pass a PSCredential directly through Invoke-Command, which then is used to update the password on the tasks. All you need to provide is the list of computers, credentials to login to those computers, and the credentials you want to update tasks for.

Behold the power of PowerShell.