Not able to create custom resources with PS

Jun 26, 2013 at 11:30 AM
When trying to generate custom resources using the create-custom-resources.ps1 powershell script like this:
.\fim-resource -uri $uri -credential $credential -debug -resourceClassTemplateFile "resource-class" $typeName -outfile "$dir\Rm${typeName}_custom.cs"
I get the following error:
Exception calling "ExpandString" with "1" argument(s): "Object reference not set to an instance of an object."
At E:\DEV\Projects\TestWebApp\fim2010client 1.0.0 src\code-generation\fim-resource.ps1:126 char:9
+         $expandedTemplate = $ExecutionContext.InvokeCommand.ExpandString($templa ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : NullReferenceException
I can see that it reads the resource and skips all default attributes like it should, but then it fails on this line:
$expandedTemplate = $ExecutionContext.InvokeCommand.ExpandString($templateContents)
The value of $templateContents at this point is:
        /// <summary>
        /// $($attribute.DisplayName)
        /// $($attribute.Description)
        /// </summary>
        public string $($attribute.CsName) {
            get { return GetString(AttributeNames.$($attribute.CsName)); }
            set { base[AttributeNames.$($attribute.CsName)].Value = value; }
        }
If i apply the "-customOnly" flag, I get "WARNING: No custom attributes found for type Contact". All non standard attributes on the "Contact"-resource is of course custom since it's a custom resource. The result in this is an empty RmContact_custom.cs class.

Any idea what I'm doing wrong here?
Coordinator
Jun 26, 2013 at 12:05 PM
Hi,
Have you created some custom attributes for your class, and also the corresponding bindings?
Cheers,
Paolo
Jun 26, 2013 at 12:51 PM
Thanks for your quick response.

Yes I have several custom attributes with bindings. I can see that the BindingDescriptions are returned by the query to $exportObjects and that the names are propagated to $attributeName.
Everything seems to be in order until it runs this line:
$expandedTemplate = $ExecutionContext.InvokeCommand.ExpandString($templateContents)
But as I said, if I try doing a -customOnly export, even on Person resource with the following script:
param(
    $dir = $pwd,
    [string] $uri = "http://localhost:5725",
    [System.Management.Automation.PSCredential] $credential,
    $typeNames = @("Person")
)

foreach ($typeName in $typeNames) {
    Write-Host "Generating partial class with custom attributes for class ${typeName}."
    & .\fim-resource -uri $uri -credential $credential -debug -customOnly -resourceClassTemplateFile "resource-custom" $typeName -outfile "$dir\Rm${typeName}_custom.cs"
}
this will just result in an empty RmPerson_custom.cs template. This happens despite having a lot of custom attributes on the Person resource.
Coordinator
Jun 26, 2013 at 1:06 PM
What about credentials? Are you passing some value? If so, the credentials you're passing can read the binding objects?
Jun 26, 2013 at 2:02 PM
I've been using default credentials, which is the FIM administrator for this instance (but also tried specifying a PSCredential).
Anyways, by putting a few Write commands in "fim-resource.ps1"I've seen that the attributes are read. The issue seems to be with the
$promotedProperty = ExpandTemplate $templateName
At this point the $templateName is "String-single"
And $attribute is:
Name Value

Name AccountName
CsName AccountName
Description User's log on name
DataType String
MemberName _accountName
Multivalued False
DisplayName Account Name


The ExpandTemplate function which fails looks like this:
function ExpandTemplate([string] ${templateFileName},[bool] ${exitIfMissing} = $false) {
    $templateFilePath = "${scriptDir}\fim-resource-templates\${templateFileName}.txt"
    if (Test-Path $templateFilePath) {
        $templateContents = [string]::Join([Environment]::NewLine,$(Get-Content $templateFilePath))
        $expandedTemplate = $ExecutionContext.InvokeCommand.ExpandString($templateContents)
        $expandedTemplate
    } elseif ($exitIfMissing) {
        Write-Error "Could not find required template file $templateFilePath"
        exit
    }
}
And as I mentioned above, the $templateContents value is
  /// <summary>
        /// $($attribute.DisplayName)
        /// $($attribute.Description)
        /// </summary>
        public string $($attribute.CsName) {
            get { return GetString(AttributeNames.$($attribute.CsName)); }
            set { base[AttributeNames.$($attribute.CsName)].Value = value; }
        }
It seems like there might be something wrong with the $templateContents variable, which is basically just read from the String-single.txt template. But I'm quite stuck here.. At this point I need to create my custom RmResource extension classes manually which is a bit of a nightmare.. ;)
Can you see anything wrong with these values? I'm running PSVersion 3.0.
Jun 27, 2013 at 6:27 AM
As I mentioned, I'm running PSVersion 3.0 and the problem seems to be related with the following PowerShell bug: Microsoft Connect

I tried using the posted workaround, and that did the trick for me. My ExpandTemplate function now looks like this:
function ExpandTemplate([string] ${templateFileName},[bool] ${exitIfMissing} = $false) {
    $templateFilePath = "${scriptDir}\fim-resource-templates\${templateFileName}.txt"
    if (Test-Path $templateFilePath) {
        $templateContents = [string]::Join([Environment]::NewLine,$(Get-Content $templateFilePath))
        
        $templateContents = (($templateContents -replace '"', '`"') -replace '''', '`''')
        $quoteChar = [char]0x2019 # Handle Unicode 'RIGHT SINGLE QUOTATION MARK'
        $replaceValue = "``$quoteChar"
        $templateContents = $templateContents -replace $quoteChar, $replaceValue
        $expandStringCommand = "`$ExecutionContext.InvokeCommand.ExpandString(""" + $templateContents + """)"
            
        $expandedTemplate = Invoke-Expression $expandStringCommand
        $expandedTemplate
    } elseif ($exitIfMissing) {
        Write-Error "Could not find required template file $templateFilePath"
        exit
    }
}
This will produce the custom Rm classes like pure magic!
Thanks for helping out. And it might be worth adding this workaround (with the version check) to you script, as it doesn't seem like it is going to be fixed anytime soon.
Coordinator
Jun 27, 2013 at 8:36 AM
Hi,

Thanks for sharing this solution, it's quite a long time I haven't generated custom classes...
There are a lot of things I'd like to do, and improving custom classes generation is one of them, but sadly I have little time (and need) to work on this anymore.
I'll try to include your workaround, anyway.

Cheers,
Paolo
Sep 22, 2014 at 10:08 PM
Thanks, helped me just in time :)