Quantcast
Channel: Microsoft Windows – Weird & Wonderful IT
Viewing all articles
Browse latest Browse all 10

Using Add-Type in a PowerShell script that is run as a Scheduled Task

$
0
0

I like using objects in PowerShell, they make management and scripting easier as your are dealing with named sets of information and not having to find objects in numbered arrays or use dictionaries.

That means however that a lot of my scripts start off with a block that looks a little like this:

 $UserDefinition = @"
    public class MyCustomUser {
       public System.String UserId;
       public System.String FirstName;
       public System.String LastName;
       public System.String Source;
       public System.Int32 Priority;
    }
 "@
 Add-Type -TypeDefinition $UserDefinition -Language CSharp
 $User = New-Object MyCustomUser

Nothing too difficult. I run a lot of scripts interactively, and this never fails (unless I get the syntax wrong inside the code block!)

However, running this exact same block of code as a Scheduled Task, with a specific domain user account failed – and the transcript showed this error:

New-Object : Cannot find type [MyCustomUser]: make sure the assembly containing this type is loaded.
At line:1 char:9
+ $User = New-Object MyCustomUser
+ ~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidType: (:) [New-Object], PSArgumentException
+ FullyQualifiedErrorId : TypeNotFound,Microsoft.PowerShell.Commands.NewObjectCommand

It turns out that when you run the above code, it generates a temporary file inside the user profile of the user that the task was configured to run as. When you run a script as a scheduled task, the task starts without waiting for the user profile to load. This means that when the Add-Type command is run, it fails. Interestingly, the command itself does not generate an error. It is only when the new object definition is attempted to be used that the command generates the error.

This behaviour is documented in a Microsoft KB article here: https://support.microsoft.com/en-us/kb/2968540. Although this is not specifically describing this error, the circumstances and effects are the same.

With this information I attempted to specify the path to generate the output from Add-Type as a parameter – as below:

Add-Type -TypeDefinition $UserDefinition -Language CSharp -OutputAssembly C:\MyScript\MyCustomUser.dll -OutputType Library

This makes no difference though, and the type still fails to be generated. The temporary files used to generate the output must still be in the profile location.

The only solution that I have made work is to pre-generate the output, and then use Add-Type pointed at the generated DLL file. So, in an interactive session I ran this:

Add-Type -TypeDefinition $UserDefinition -Language CSharp -OutputAssembly C:\MyScript\MyCustomUser.dll -OutputType Library

And then in the script in the scheduled task we changed the import to run this:

Add-Type -Path C:\MyScript\MyCustomUser.dll

The script now runs every time without error. The only annoyance is that if we ever change the definition of the object that we have to regenerate the DLL file. This would be a bigger issue if you were dynamically building custom types and then importing them at runtime.

Hopefully this might help someone else from wondering why their script breaks when run as a scheduled task.


Viewing all articles
Browse latest Browse all 10

Latest Images

Trending Articles





Latest Images