Skip to main content

How to create a PowerShell script

PowerShell  is an amazing tool which we can use to perform various operations in windows environments. Today we are going to write a PowerShell  script using Windows PowerShell  ISE.

How to open Windows PowerShell ISE 

For this session we need to have Windows PowerShell  ISE. You can find it under, Control Panel\All Control Panel Items\Administrative Tools.
You better open Windows PowerShell  ISE as administrator mode. if you have any issues please follow this link. Windows PowerShell Integrated Scripting Environment (ISE)

In My project I had to use PowerShell script to regiter few Dlls in Global Assembly Cache (GAC) and keep file paths in XML file and extract data by reading XML file. My XML file looks like this and file name is FilePath.XML.

FilePath.XML

<?xml version="1.0" encoding="utf-8"?>
<Resource>
  <MacroFilePath>\ReleaseBuild\ReleaseMacro.mac</MacroFilePath>
  <ProductName>BCS</ProductName>
  <GPVersion>GP2016</GPVersion>
  <CompatiblityID>16</CompatiblityID>
  <MajorVersion>16</MajorVersion>
  <MinorVersion>0</MinorVersion>
  <BuildNumber>117</BuildNumber>
  <AutoUpdateBuildNumber>0</AutoUpdateBuildNumber>
  <FormDictionary>BCSF.DIC</FormDictionary>
  <ReportDictionary>BCSR.DIC</ReportDictionary>
  <DefaultChunk>BCS.CNK</DefaultChunk>
  <DefaultExtract>BCS.DIC</DefaultExtract>
  <DefaultGPSDKDirectory>GP2016 VS Tools SDK</DefaultGPSDKDirectory>
  <GacUtilLocation>C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools</GacUtilLocation>
  <PackagingLocation></PackagingLocation>
  <DictionaryPath></DictionaryPath>
  <ExtractPath></ExtractPath>
  <ChunkPath></ChunkPath>
  <DefaultLocation>ReleaseBuild</DefaultLocation> 
  <AssemblyLocaion></AssemblyLocaion>
  <ChunckLocation></ChunckLocation>
  <GpLocaion></GpLocaion>
  <GPVSToolsSDK></GPVSToolsSDK>
  <DynamicsSetLocaion>C:\Program Files (x86)\Microsoft Dynamics\GP2016\DYNAMICS.SET</DynamicsSetLocaion>
</Resource>

GetSource.ps1

Now I need to read this XML file from PowerShell  script. In order to do that i have written a script call GetSource.ps1. There I can pass a node as parameter which I need to read the value.

#GET SOURCE
#==========================================================================================================================================================================
Function GetSource ([string] $NodeToFind)
{
    try{
        $invocation = (Get-Variable MyInvocation).Value
        $directorypath = $invocation.PSScriptRoot
        $parentPath = Split-Path -parent $directorypath

        if([string]::IsNullOrEmpty($parentPath))
        {
            $XMLPath = $directorypath  + '\FilePath.xml'
            #$XMLPath = $directorypath  + '\ResourceFile.xml'
        }
        else
        {
            $XMLPath = $parentPath  + '\FilePath.xml'
        }

        [xml]$xml= [xml](Get-Content $XMLPath)

        [string] $Source = $xml.GetElementsByTagName($NodeToFind).InnerXML

        return $Source;
      }
      catch{
            throw $_
            return
        }
}
#========================================================================================================================================================================== 

CopyFiles.ps1

Now I'm going to write PowerShell  function to copy required file to given destinations. This function is a general one which we can pass Source and Destination as Parameters and get the files copied.

#COPY DLLS
#==========================================================================================================================================================================
Function Copy-Required-DLLs([string] $Source, [string] $Destination){

    while(1){
        try{

            if( Test-Path $Source.Trim())
            {           
                Copy-Item $Source $Destination
                Write-host "$Source Copied to $Destination"
                return
            }
            else
            {
                Write-Error "File $Source not found"
                exit
            }
        }
        catch [System.IO.IOException] {
            if($_.Exception.HResult -eq -2147024864){
                Start-Sleep -Milliseconds 500
                Write-Host '-' -NoNewline
            }else{
                throw $_
                return
            }
}
        catch{
            throw $_
            return
        }
    }
}
#==========================================================================================================================================================================


RegisterAssembly.ps1

Then we need to register all the copied DLLs in Global Assembly cache (GAC). To make that happen we are going to write another PowerShell  Script. In this script we are going to pass file info as a parameter and also we are going to refer GetSource.ps1 and  use GetSource function to read FilePath.XML file.

$this_path is a variable that holds the execution directory path and 
[System.IO.DirectoryInfo](Split-Path((Get-Variable MyInvocation).Value.MyCommand.Path)) returns the execution path.


$this_path = [System.IO.DirectoryInfo](Split-Path ((Get-Variable MyInvocation).Value.MyCommand.Path))
.$this_path\GetSource.ps1

#REGISTER DLLS
#==========================================================================================================================================================================
Function Register-Required-Dlls{
    Param(
        [Parameter()]
        [IO.FileInfo]$Dll
    )
    while(1){
        try{
            if($Dll.Exists){           
                [string] $GacUtilLocation =  GetSource -NodeToFind "GacUtilLocation";
                Set-Location -Path $GacUtilLocation

                .\gacutil.exe /i $Dll
                Write-Verbose "$Dll Installed.."
                return
            }else{
                Write-Error "File $Dll not found"
                exit
            }
        }
        catch [System.IO.IOException] {
            if($_.Exception.HResult -eq -2147024864){
                Start-Sleep -Milliseconds 500
                Write-Host '-' -NoNewline
            }else{
                throw $_
                return
            }
}
        catch{
            throw $_
            return
        }
    }
}

#==========================================================================================================================================================================

Finally we are going to assemble the peaces we have written into a script which we can achieve the goal. Now we are creating PowerShell  script called RegisterForMaualProcess.ps1.

RegisterForMaualProcess.ps1

$this_path = [System.IO.DirectoryInfo](Split-Path ((Get-Variable MyInvocation).Value.MyCommand.Path))

.$this_path\RegisterAssembly.ps1
.$this_path\CopyFiles.ps1


[string] $MyAssembly = GetSource -NodeToFind "AssemblyLocaion"  ;
[string] $GpLocaion = GetSource -NodeToFind "GpLocaion" ; 
[string] $GPVSToolsSDK = GetSource -NodeToFind "GPVSToolsSDK" ;
[string] $ChunckLocation =  GetSource -NodeToFind "ChunckLocation" ;
[string] $DefaultLocation =  GetSource -NodeToFind "DefaultLocation";
[string] $DefaultChunk =  GetSource -NodeToFind "DefaultChunk";
[string] $GPVersion =  GetSource -NodeToFind "GPVersion";


#If null or empty set Default
if ([string]::IsNullOrEmpty($MyAssembly))
{
    [string] $AssemblyPath = Split-Path ($this_path)
    $MyAssembly = "$AssemblyPath" +"\GP.Interop.dll"
}
if ([string]::IsNullOrEmpty($GpLocaion))
{
    $GpLocaion = "C:\Program Files (x86)\Microsoft Dynamics\"+"$GPVersion\"
}
if ([string]::IsNullOrEmpty($GPVSToolsSDK))
{
    $GPVSToolsSDK = "C:\Program Files (x86)\Microsoft Dynamics\"+"$GPVersion VS Tools SDK\"
}
if([string]::IsNullOrEmpty($ChunckLocation))
{       
    $ChunckLocation = "$this_path\" + $DefaultChunk;
}


#COPY GP.Interop.dll
#==========================================================================================================================================================================
Write-Host "Start to copy GP.Interop.dll..."                                 
Copy-Required-DLLs -Source $MyAssembly -Destination $GpLocaion -v
Write-Host "GP.Interop.dll copied to $GPVersion" -foregroundcolor "yellow"

Copy-Required-DLLs -Source $MyAssembly -Destination $GPVSToolsSDK -v
Write-Host "GP.Interop.dll copied to $GPVersion VS Tools SDK" -foregroundcolor "yellow"

Copy-Required-DLLs -Source $MyAssembly -Destination C:\Windows\Microsoft.NET\Framework\v2.0.50727 -v
Write-Host "GP.Interop.dll copied to $GPVersion VS Tools C:\Windows\Microsoft.NET\Framework\v2.0.50727" -foregroundcolor "yellow"
Write-Host "Done..." -foregroundcolor "green"
#==========================================================================================================================================================================

Register-Required-Dlls C:\Windows\Microsoft.NET\Framework\v2.0.50727\GP.Interop.dll -v

when you run the program, these files we need to keep that in the execution path since it refers each other.



Comments

Popular posts from this blog

How to connect blob storage via Shared access signature URL (SAS)

  Follow the steps to connect the blob container using the  Shared access signature. You may need  Azure Storage Explorer    in order to access the blob storage locally. STEP 1   Under  Local & Attached   go to   Storage Accounts ( Right-click ) ->   Connect to Azure Storage . STEP 2 Select the  Blob container   option. STEP 3 Select the  Shared access signature URL (SAS)   option. STEP 4 Copy and paste the given  Blob container SAS URL   and click   Next . STEP 5 Click  Connect . You are all set to access to content of the blobs storage. 👍

Dynamics GP- How to use custom .Net assembly in Dexterity

Let's take a scenario that we need to develop as dexterity script using a .net assembly/DLL program inside the Dexterity script itself. We have to create the assembly/DLL which we need to use or else use from .net framework. In Visual Studio we have to create a class library project. Provide Name as you want in your project. In my case, i have given the name as MyAssembly . Add a new class to the project. Make sure that the access modifier of that class is public . Also, d efine public properties you need to access from the  Dexterity script.                              public class   ExtraFields {        public   string   Description   { get;set; }     public   List <Field>   FieldList  =  new   List< Field > (); } public class   Field {         public   string   Id   { get;set; }    public   string   Value   { get;set; } } Compile your project. In order to use this assembly program in your Dexterity script, you