Integrate PowerShell to Extend Your Migration Process
Learn more about how to use CopyRight2's PowerShell Integration Add-on to integrate PowerShell Cmdlets into your ActiveScript transformations defined in your migration jobs settings (object transformation scripts, job start/end scripts, copy start/end scripts).
Usually you would use transformation scripts for users, groups or contacts in your migration job to apply changes to the migrated objects. For example, if performing an Active Directory migration of users or groups between two different Active Directory forests, you may need to assign the content of one Active Directory attribute to an attribute having a different name in the target forest's schema. Or you may need to calculate the value of an attribute with some sort of algorithm to establish a naming convention, such as an email address that should be based on other attributes values (like first-name.last-name@domain-name). During a file server migration you may want to implement additional configuration steps for each source & destination folder pair copied.
PowerShell provides access to local and remote management of not only Windows® and many applications running on Windows® such as Microsoft® Exchange but also to other platforms like macOS® and Linux systems.
With the PowerShell Integration Add-on you get the ability call PowerShell code from your transformation scripts.
Table of Contents:
- How to Execute PowerShell Code
- Executing PowerShell Code as a Sub-Routine
- Executing PowerShell Code as a Function
- Passing Parameters to PowerShell Cmdlets
- Handling Lists of Variants (1-Dimensional Arrays)
- Handling Tables of Variants (2-Dimensional Arrays)
- How to Differentiate Between Empty Return Value and Empty String
- How to Add Additional PowerShell Snap-Ins
How to Execute PowerShell Code
Before you can use PowerShell code in your ActiveScript scripts, you will need to download the PowerShell Integration Add-on from the CopyRight2 download page and install it.
The Add-on enables executing PowerShell code from ActiveScript by prefixing a line of code with the '#' character.
You can call cmdlets as sub-routine, not having a return value or as a function returning some information to your ActiveScript.
Executing PowerShell Code as a Sub-Routine
If calling a cmdlet as a sub-routine the cmdlet’s output will get appended to the job’s log file automatically.
The example below would call PowerShell's write-output cmdlet and write the text "Hello World" to the job's log file during execution:
#write-output "Hello World"
Call PowerShell as Sub-Routine to Write Something to Log File Using Write-Output Cmdlet
Executing PowerShell Code as a Function
In case of a function, the add-on will automatically convert the returned data into either a single variant, a list of variants (1-dimensional) or a table of variants (2-dimensional).
If the cmdlet is called as a function the output will not get logged by default, unless you set the log level for the ActiveScript component in Options -> Extended Logging to at least level 3.
The example below shows how to redirect the output of the write-output cmdlet to an ActiveScript variable called psOutput and then display the content in a message box:
psOutput=#write-output "Hello World"
Redirect PowerShell Output to an ActiveScript Variable and Display its Content in a Message Box
Passing Parameters to PowerShell Cmdlets
So far we have called PowerShell code as a sub-routine and as a function. Now we will have a look at how to pass parameters to the PowerShell code.
It is possible to pass parameters using ActiveScript variables and ActiveScript functions when calling PowerShell cmdlets.
The example below calls CopyRight2’s Destination() ActiveScript function to retrieve the content of the samAccountName attribute for the object currently being migrated. Additionally you can see how to combine it with a Select to filter the output by the Sid attribute.
Important: “Sid” has to be put inside of double quotes to differentiate from an ActiveScript variable called Sid.
sid = #get-localuser Destination("samAccountName") | select "Sid"
MsgBox "SID=" & sid
Call Get-Localuser Cmdlet for the Current Target User Filtering by SID Attribute Using Select
Handling Lists of Variants (1-Dimensional Arrays)
So far we have seen how to deal with simple Variants being returned from PowerShell, for example a single string.
If the PowerShell code executed returns a list of strings for example, you can use ActiveScript’s UBound() function on the returned Variant to get the upper bound. The index begins at zero to access the first element of the list.
In the example below you can see how to treat a list of Variants, for example a list of user account names for all local users found on a system:
userNames=#get-localuser | select "Name"
for i = 0 to UBound(userNames)
Call Get-Localuser Cmdlet for all Local Users Filtering by Name Attribute | List of Variants
Handling Tables of Variants (2-Dimensional Arrays)
There are cases where PowerShell will return a table with one or more rows having more than one column.
You can access that data similar to a list.
Instead of a single dimension, there are now 2 dimensions for the rows (first dimension) and columns (second dimension). You can use ActiveScript's UBound() function to query for each dimension's upper bound.
The example below shows how to call the get-localuser cmdlet, filtering by "Sid", "Description" and the "Name" attribute and then displaying the content of each cell from left to right and top down:
localUsers=#get-localuser | select "Sid", "Description", "Name"
MsgBox "Rows=" & UBound(localUsers, 1) + 1
MsgBox "Cols=" & UBound(localUsers, 2) + 1
for r = 0 to UBound(localUsers, 1)
for c = 0 to UBound(localUsers, 2)
MsgBox localUsers(r, c)
Call Get-LocalUser Cmdlet for Local Users Filtering by Sid, Description & Name | Table of Variants
How to Differentiate Between Empty Return Value and Empty String
A call will return a Variant of type VT_Empty, in case of something that has no value set to differentiate from the case where an empty string ("") is returned.
The example below shows how to check a returned Variant for emptiness by using ActiveScript's IsEmpty() function:
var=#ps-cmdlet | select "SomeAttribute"
if IsEmpty(var) then
MsgBox “Var is empty”
MsgBox “Var is not empty”
Test if a Returned Value is Empty Using IsEmpty()
How to Add Additional PowerShell Snap-Ins
You can execute PowerShell's Add-PSsnapin cmdlet to allow calling additional cmdlets, for example the Exchange Management PowerShell Snap-in providing you with cmdlets to manage Microsoft Exchange.
Usually such a call would be added to your Job Start script to let it execute only once and not multiple times during the execution of a user or group transformation script where it would get called every time such an object is migrated.
The example below shows how to include the Microsoft.Exchange.Management.PowerShll.SnapIn:
#Add-PSsnapin -Name "Microsoft.Exchange.Management.PowerShell.SnapIn" -ErrorAction "SilentlyContinue"
Add Additional PowerShell Snap-in From Job Start Script to Execute Only Once
Using PowerShell from your object transformation scripts is very easy and provides you with endless possibilities. If you should want to learn more about this topic, you could read our "Migrate Users from Account Forest to Exchange Resource Forest" blog posting based on an actual user scenario.
If you should have any feedback, positive or negative or some follow-up questions, please let us know in the comments below. Thank you!