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