PowerShell DSC Journey – Day 21

Alright, when I left off I had added in some testing for the $Credential Property of the Resource in the Get-TargetResource and Test-TargetResource functions. Today I am going to do the same with Set-TargetResource, and then test my Configuration to see what I did wrong. If I survive that I will try to create a Hardware Profile with my Resource.

First things first, I add this same section to Set-TargetResource.

#Check to see if Credential and VMMServer is valid
    $ResourceVMMServer = Get-SCVMMServer -ComputerName $VMMServer -Credential $Credential

I think that is all I need to do here because Get-SCHardwareProfile and Set-SCHardwareProfile don’t require a credential.

I run my first test, and everything works great except the test removed the DVD Drive. Which it wasn’t supposed to do. And there is all some verbage for the CPU Count that is incorrect, and it looks like I need to add a case for when CPUCount is not specified.

PS C:\Scripts> Set-TargetResource -Name "DSCWEB Hardware Profile" -VMMServer MY-VMM-SERVER1 -Ensure Present -Verbose
cmdlet Set-TargetResource at command pipeline position 1
Supply values for the following parameters:
VERBOSE: VMMServer is MY-VMM-SERVER1
VERBOSE: Hardware Profile Name is DSCWEB Hardware Profile
VERBOSE: Loading module from path 'C:\Program Files\Microsoft System Center 2012 R2\Virtual Machine Manager\bin\virtualmachinemanager.R2Aliases.ps1'.
VERBOSE: Loading module from path 'C:\Program Files\Microsoft System Center 2012 R2\Virtual Machine Manager\bin\VirtualMachineManagerLibraryClientCleanup.ps1'.
VERBOSE: Loading module from path 'C:\Program Files\Microsoft System Center 2012 R2\Virtual Machine Manager\bin\psModules\virtualmachinemanager\..\..\virtualmachinemanager.R2AdvFunc.psm1'.
VERBOSE: Loading module from path 'C:\Program Files\Microsoft System Center 2012 R2\Virtual Machine Manager\bin\psModules\virtualmachinemanager\..\..\Microsoft.SystemCenter.VirtualMachineManager.dll'.
VERBOSE: Checking if the Hardware Profile DSCWEB Hardware Profile exists
VERBOSE: The Hardware Profile was found
VERBOSE: Ensure set to Present

MostRecentTaskIfLocal : Remove virtual DVD drive

VERBOSE: DVDDrive has been removed
VERBOSE: CPUCount is DSCWEB Hardware Profile.CPUCount, should be 0
Set-SCHardwareProfile : Cannot validate argument on parameter 'CPUCount'. The 0 argument is less than the minimum allowed range of 1. Supply an argument that is greater than or equal to 1 and then try the 
command again.
At line:97 char:80
+ ...      Set-SCHardwareProfile -HardwareProfile $Name -CPUCount $CPUCount
+                                                                 ~~~~~~~~~
    + CategoryInfo          : InvalidData: (:) [Set-SCHardwareProfile], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.SystemCenter.VirtualMachineManager.Cmdlets.SetHWConfigCmdlet
 
VERBOSE: CPUCount Set to 0
VERBOSE: No VMNetwork was specified

Ok, let’s tackle the DVD Drive issue first. I didn’t specify an option for it, it was already present, and the profile was set to Ensure = Present, so it should not have been removed. Here is the code block.

 If($DVDDrive -eq $ResourceHWProfile.VirtualDVDDrives.Enabled)
                    {
                        Write-Verbose "DVDDrive is already set properly"
                    }
                    Else
                    {
                        If($DVDDrive -eq $True)
                        {
                            New-SCVirtualDVDDrive -HardwareProfile $Name -LUN 1 -Bus 0
                            Write-Verbose "DVDDrive has been created"
                        }
                        Else
                        {
                            Get-SCVirtualDVDDrive -HardwareProfile $Name | Remove-SCVirtualDVDDrive
                            Write-Verbose "DVDDrive has been removed"
                        }
                    }

What is happening is I am not specifying a value for the DVDDrive Property. So as far as it is concerned, the last Else statement gets executed. I am going to need to add a case for not specifying the DVDDrive Property. I reconfigured this code to look like this instead.

If($DVDrive)
                    {
                        If($DVDDrive -eq $ResourceHWProfile.VirtualDVDDrives.Enabled)
                        {
                            Write-Verbose "DVDDrive is already set properly"
                        }
                        Else
                        {
                            If($DVDDrive -eq $True)
                            {
                                New-SCVirtualDVDDrive -HardwareProfile $Name -LUN 1 -Bus 0
                                Write-Verbose "DVDDrive has been created"
                            }
                            Else
                            {
                                Get-SCVirtualDVDDrive -HardwareProfile $Name | Remove-SCVirtualDVDDrive
                                Write-Verbose "DVDDrive has been removed"
                            }
                        }
                    }
                    Else
                    {
                        Write-Verbose "No setting specified for DVDDrive.  No changes made"
                    }

And that works exactly like it should. Now I need to do the same thing for CPUCount. This also works just fine. And it’s also at this point that I realize that I already have the VMNetwork parameter setup that way. Apparently it never occurred to me I would need to do the same thing for the others. Oh well. Moving along! I run a few more test and make a few more minor changes and tweaks but I am not going to bore you with those details. I just needed to update the part of the function that creates a new Hardware Profile with the same If checks as above.

And now. Let’s see how badly I have failed here. Let’s test this bad boy.

PS C:\Scripts> Test-xDscSchema -Path 'C:\Program Files\WindowsPowerShell\Modules\cSCVMM\DSCResources\cSCVMM_Hardware\cSCVMM_Hardware.schema.mof' -Verbose
VERBOSE: The path to the schema file has been verified.
VERBOSE: The schema file has passed mofcomp's syntax check.
VERBOSE: Testing the schema file's compliance to Desired State Configuration's contracts.
VERBOSE: Perform operation 'Get CimClass' with following parameters, ''namespaceName' = root\microsoft\windows\DesiredStateConfiguration,'className' = tmp65B2'.
VERBOSE: Operation 'Get CimClass' complete.
True

Pretty good. So far. I don’t expect this to continue.

PS C:\Scripts> Test-xDscResource -Name cSCVMM_Hardware -Verbose
VERBOSE: Testing the schema.mof file.
VERBOSE: The path to the schema file has been verified.
VERBOSE: The schema file has passed mofcomp's syntax check.
VERBOSE: Testing the schema file's compliance to Desired State Configuration's contracts.
VERBOSE: Perform operation 'Get CimClass' with following parameters, ''namespaceName' = root\microsoft\windows\DesiredStateConfiguration,'className' = tmp9D53'.
VERBOSE: Operation 'Get CimClass' complete.
VERBOSE: Testing the .psm1 file.
VERBOSE: Loading module from path 'C:\Program Files\WindowsPowerShell\Modules\cSCVMM\DSCResources\cSCVMM_Hardware\cSCVMM_Hardware.psm1'.
VERBOSE: Importing function 'Get-jnx34np3.c3iTargetResource'.
VERBOSE: Importing function 'Set-jnx34np3.c3iTargetResource'.
VERBOSE: Importing function 'Test-jnx34np3.c3iTargetResource'.
VERBOSE: The schema.mof and .psm1 files were both indivually correct.
VERBOSE: Result of testing Get-TargetResource for it's mandatory properties: True.
VERBOSE: Result of testing Set-TargetResource for no read properties: True.
VERBOSE: Result of testing Get-TargetResource for no read properties: True.
True

Well. That was unexpected. I guess on to the next thing. Let’s try my Configuration again. Here is my current Configuration.

Configuration TestSCVMMHardware
{

    param
    (
        [pscredential]$Credential = (Get-Credential)
    )

    Import-DscResource -Module cSCVMM

    node localhost
    {
        cSCVMM_Hardware MyHardwareProfile
        {
            VMMServer = "MY-VMM-SERVER1"
            CPUCount = 2
            DVDDrive = $True
            Ensure = "Present"
            Name = "Jacobs Profile"
            VMNetwork = "Server Traffic"
       }
BOOM!  RED TEXT NATION!
 
PS C:\Scripts> C:\users\jacob.benson\SkyDrive\PowerShell\DSC\TestSCVMMHardware.ps1
cmdlet Get-Credential at command pipeline position 1
Supply values for the following parameters:
cSCVMM\cSCVMM_Hardware : Class 'cSCVMM_Hardware' requires that a value of type 'MSFT_Credential' be provided for property 'Credential'.
At C:\users\jacob.benson\SkyDrive\PowerShell\DSC\TestSCVMMHardware.ps1:13 char:9
+         cSCVMM_Hardware MyHardwareProfile
+         ~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [Write-Error], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : MissingValueForMandatoryProperty,cSCVMM\cSCVMM_Hardware
 
Errors occurred while processing configuration 'TestSCVMMHardware'.
At C:\windows\system32\windowspowershell\v1.0\Modules\PSDesiredStateConfiguration\PSDesiredStateConfiguration.psm1:2203 char:5
+     throw $errorRecord
+     ~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (TestSCVMMHardware:String) [], InvalidOperationException
    + FullyQualifiedErrorId : FailToProcessConfiguration

}

}

Alright. So….I declared my credential variable to be of the type [pscredential]. Maybe it needs to be [MSFT_Credential]? Let’s try it. But wait, I have the bright idea that I should check to see how the ADDomain resource handles it, and I find my answer in the .psm1 file for the resource.

	[Required, EmbeddedInstance("MSFT_Credential")] String DomainAdministratorCredential;
	[Required, EmbeddedInstance("MSFT_Credential")] String SafemodeAdministratorPassword;
	[write,EmbeddedInstance("MSFT_Credential")] String DnsDelegationCredential;

Looks like I need to update my Resource.

PS C:\Scripts> $Credential = New-xDscResourceProperty -Name Credential -Type MSFT_Credential -Attribute Required -Description "Valid credential for connecting to VMM Server"
New-xDscResourceProperty : Cannot validate argument on parameter 'Type'. The argument "MSFT_Credential" does not belong to the set "Uint8,Uint16,Uint32,Uint64,Sint8,Sint16,Sint32,Sint64,Real32,Real64,Char16,Strin
g,Boolean,DateTime,Hashtable,PSCredential,Uint8[],Uint16[],Uint32[],Uint64[],Sint8[],Sint16[],Sint32[],Sint64[],Real32[],Real64[],Char16[],String[],Boolean[],DateTime[],Hashtable[],PSCredential[]" specified by 
the ValidateSet attribute. Supply an argument that is in the set and then try the command again.
At line:1 char:63
+ ... w-xDscResourceProperty -Name Credential -Type MSFT_Credential -Attrib ...
+                                                   ~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidData: (:) [New-xDscResourceProperty], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,New-xDscResourceProperty

Hmmm. How else would you get the schema.mof to show that Type? Then I look at the schema.mof for my resource and get my answer.

	[Required, EmbeddedInstance("MSFT_Credential"), Description("Valid credential for connecting to VMM Server")] String Credential;

So the type Credential, automatically changes to that in the schema. Good to know. Now I try my Resource using [MSFT_Credential]$Credential and that fails.

PS C:\Scripts> C:\users\jacob.benson\SkyDrive\PowerShell\DSC\TestSCVMMHardware.ps1
cmdlet Get-Credential at command pipeline position 1
Supply values for the following parameters:
TestSCVMMHardware : Unable to find type [MSFT_Credential]. Make sure that the assembly that contains this type is loaded.
At C:\users\jacob.benson\SkyDrive\PowerShell\DSC\TestSCVMMHardware.ps1:27 char:1
+ TestSCVMMHardware -Credential (Get-Credential)
+ ~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (MSFT_Credential:TypeName) [], RuntimeException
    + FullyQualifiedErrorId : TypeNotFound

This has me stumped. Nothing of use in the DSC Event Logs. Comparing my .psm1 file to the ADDomain.psm1 file, I notice that all of their credentials are of the type [PSCredential] while mine is of the type [System.Management.Automation.PSCredential]. Which is weird (I think?). I try to change the parameter in my Configuration to the type [System.Management.Automation.PSCredential] but I get the same error. So I am going to change the .psm1 type to just [pscredential] and see what happens. I reloaded everything and change the type for Credential back to [PSCredential] and the same thing still happens.

I am stumped. Going to call it a day on that front.

Edit: Thanks to Jason Hofferle for helping figure out what I was doing wrong (and it was something dumb). I was so wrapped up in the thought that I did something wrong in my Resource that I didn’t bother to specify the Credential property in my actual Configuration.

        cSCVMM_Hardware MyHardwareProfile
        {
            VMMServer = "MY-VMM-SERVER1"
            CPUCount = 2
            DVDDrive = $True
            Ensure = "Present"
            Name = "Jacobs Profile"
            VMNetwork = "Server Traffic"
            Credential = $Credential
       }

Default Microsoft Active Directory Certificate Services URL

For my own reference (since I spent 30 minutes figuring this out and couldn’t find it documented anywhere) and to hopefully save someone else time.

After installing AD Certificate Services Web Enrollment, you need a URL to go to request and download certificates.  But, what is that default URL?

http://SERVERNAME/certsrv/en-us

Where SERVERNAME is where the AD CS Web Enrollment is installed.