C# cmdlet dll that references other project dll fails on load - c#

I have a C# project used as PowerShell cmdlet - this should be the API to the main function of a product - so I have to reference a lot of dll's in my PowerShell library.
My problem is that customers want to load the PowerShell dll from any location without settings the working directory to the program folder where all dll's are located. But I only can use my PowerShell commands if I open Powershell by a shortcut where the working dir is set to the program files folder like this:
C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe -noexit -command "[reflection.assembly]::loadFrom('.\PSAPI.dll') | import-module"
and set also the working dir to my program files folder where the product is already installed.
If I just use
[Reflection.Assembly]::LoadFile("C:\Program Files(x86)\MyProduct\PSAPI.dll")
or
[Reflection.Assembly]::LoadFrom("C:\Program Files(x86)\MyProduct\PSAPI.dll")
it always fails. Is there a solution for that (without copying all files to PowerShell folder)?
Here is what I try and the error I get - I can't set the referenced dll's in other way - the .NET application is looking in the working dir for referenced dll's - I set the working dir in powershell to ensure I'm in the right directory, but it won't load my module
[reflection.assembly]::loadFrom( 'C:\Program Files (x86)\ASG-Remoteesktop 2016\ASGRD-PSAPI.dll' ) | import-module
Exception calling "LoadFrom" with "1" argument(s): "Could not load file or
assembly 'file:///C:\Program Files (x86)\ASG-Remoteesktop
2016\ASGRD-PSAPI.dll' or one of its dependencies. The system cannot find the
file specified."
At line:1 char:1
+ [reflection.assembly]::loadFrom( 'C:\Program Files (x86)\ASG-Remoteesktop
2016\A ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : FileNotFoundException

Guessing here as you haven't provided the error but if it works from the same directory and not from another, it's probably that the C# DLL uses relative paths.
When the current directory is C:\Program Files(x86)\MyProduct it doesn't matter if you use the full path or just Resources\MyFile.dat, both will end up at the same place. However if you are in root C: the relative path will look for C:\Resources\MyFile.dat which of course doesn't exist. When you use C:\Program Files(x86)\MyProduct\Resources\MyFile.dat it doesn't matter what the current directory is, it will always work.
Check your C# DLL for any relative paths and either temporarily change the working directory or use absolute paths instead.

One approach could be: add your assembly path C:\Program Files(x86)\MyProduct to PSModulePath environment variable. Once that is done, you can execute import-module -name <name of your module> and it will load it from your folder. In that case you won't need to load your assembly explicitly (most probably).
For more details execute following command in powershell and check the details given for -name parameter.
get-help import-module -detailed

Related

Code build artifacts are not packed correctly

I am using AWS Pipeline to deploy a .NET Framework application but I am stuck while trying to create the zip file for Code Deploy.
The source and build steps are passing but when trying to create the package for Code Deploy, something odd is happening.
Here is my folder structure:
Project
-Source
-Base
-CoreAPI
-Api
- bin
- scripts
- appspec.yml
- ...
-Database
- ...
-Nuget
- ...
After the build, I want to create a zip file with all files and folders within "Project\Source\Base\CoreAPI\Api"
Here is a part of the buildspec.yml which relates to artifacts:
artifacts:
files:
- '**/*'
name: "api-build-artifact"
base-directory: .\Source\Api\CoreAPI\Api
As a result code build creates a zip file with all the files and folders within "Source", basically it discards the "base-directory".
I tried some variations like these:
artifacts:
files:
- '.\Source\Base\CoreAPI\Api\**\*'
But then I get a zip with the folder structure Source\Base\CoreAPI\Api + all files and folders and obviously, Code Deploy fails because the "appspec.yml" file is not in the root folder.
Any idea what might be wrong here?
Your indentation under artifacts is wrong. Try this:
artifacts:
files:
- '**/*'
name: "api-build-artifact"
base-directory: .\Source\Api\CoreAPI\Api
discard-paths: yes
Ref:
https://docs.aws.amazon.com/codebuild/latest/userguide/build-spec-ref.html

Windows Server 2012: Powershell is not recognizing NuGet

I am facing a situation where nuget.exe is not being recognized by Powershell in Windows Server 2012. I am pretty sure that the environment variable has been correctly set. Yet I am getting the following error:
nuget : The term 'nuget' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the
path is correct and try again.
At line:1 char:1
+ nuget
+ ~~~~~
+ CategoryInfo : ObjectNotFound: (nuget:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
I am getting the same error even if I go to the directory where nuget.exe is present and execute nuget.
Windows CMD is showing nuget is not a recognized command, but it's working fine if I execute nuget inside a directory where nuget.exe is present.
Am I making a mistake in setting up environment variable for nuget? Please help :)
Note: I am new to dotnet tech ecosystem.
Like a lot of Unix systems, Powershell doesn't include current directory in the path. One needs to either use full path or explicitly include current directory.
Try .\nuget.exe in Nuget's directory.
As explained in the documentation,
As a security feature, PowerShell does not run executable (native)
commands, including PowerShell scripts, unless the command is located
in a path that is listed in the Path environment variable $env:path or
unless you specify the path to the script file.
Your path variable should be a Semi-colon separated list of paths containing your directories: On one of my Server 2012 boxes it looks like this:
%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem;%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\;C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\110\Tools\Binn\;C:\Program Files (x86)\Microsoft SQL Server\120\Tools\Binn\;C:\Program Files\Microsoft SQL Server\120\Tools\Binn\;C:\Program Files\Microsoft SQL Server\120\DTS\Binn\;C:\Program Files (x86)\Microsoft SQL Server\120\Tools\Binn\ManagementStudio\;C:\Program Files (x86)\Microsoft SQL Server\120\DTS\Binn\;C:\ProgramData\chocolatey\bin;C:\Program Files (x86)\Windows Kits\10\Windows Performance Toolkit\;C:\Windows\SysWOW64\WindowsPowerShell\v1.0\Modules\TShell\TShell\;C:\Program Files\dotnet\;C:\Program Files\nodejs\;C:\Program Files (x86)\dotnet\
which is a bit long and awkward. You should append your path to NuGet to this string and save it.
From Windows Explorer, right click on This PC => Properties. Locate Advanced system settings on the the left hand Panel. Choose the Advanced tab. Click on the Environment Variables button on the bottom right. Scroll the window down until you find the Path variable.
I usually copy and paste it to/from a text editor for ease of use.

Installing PsychoPy as a third party package in Ironpython

I've been using IronPython to use functions in a C# .dll class library. I have also been using another set of packages called Psychopy. However, IronPython does not recognize Pyschopy packages. I tried placing a .pth file that said the following in IronPython's site-packages folder: C:/Program Files (x86)/PsychoPy2/Lib/site-packages/PsychoPy-1.80.03-py2.7.egg
I then changed the sys.prefix, sys.exec_prefix variables in site.py to "C:/Program Files (x86)/IronPython 2.7". Then, I went to the command line and in the ironpython shell, I tried to import psychopy. I received the following error:
Traceback (most recent call last):
File "<stdin>", line 1, in '<'module'>'
File "C:\Program Files (x86)\PsychoPy2\Lib\site-packages\PsychoPy-1.80.03-py2.7.egg\psychopy\__init__.py", line 33, in '<'module'>'"
File "C:\Program Files (x86)\PsychoPy2\Lib\site-packages\PsychoPy-1.80.03-py2.7.egg\psychopy\preferences\__init__.py", line 5, in '<'module'>'
File "C:\Program Files (x86)\PsychoPy2\Lib\site-packages\PsychoPy-1.80.03-py2.7.egg\psychopy\preferences\preferences.py", line 186, in '<'module'>'
File "C:\Program Files (x86)\PsychoPy2\Lib\site-packages\PsychoPy-1.80.03-py2.7.egg\psychopy\preferences\preferences.py", line 32, in __init__
File "C:\Program Files (x86)\PsychoPy2\Lib\site-packages\PsychoPy-1.80.03-py2.7.egg\psychopy\preferences\preferences.py", line 95, in getPaths
File "C:\Program Files (x86)\IronPython 2.7\Lib\os.py", line 423, in __getitem__
KeyError: HOME
I was wondering if anyone know how to install thrid party packages in Ironpython.
I'm guessing that you can fix this by adding HOME as an environment variable (System properties>Advanced) and pointing it to your home folder.
I'm not sure why that step is needed for IronPython but not for regular C python - I guess C Python creates it if it isn't found?
I also don't know what else will go wrong in PsychoPy; I've never used IronPython
Jon

Storing settings for a nuget package. Is there a better way?

I have a console application that is available via nuget or on it's own. It gets installed into the tools directory for the NuGet package. The application requires 3 pieces of 'configuration' information.
a database connection string
a folder path
one more configuration option (string)
Currently, I store these configuration values in a text file right next to the exe in a file called settings.js, serialized as json.
When the application first runs, if the file is not present, it creates one with default values.
I keep the settings.js file in this location so the file will get checked into source control.
My question is about maintaining the settings file across versions.
If you Update-Package via nuget, everything works great, except the new version doesn't have any settings i had configured, because there is a new folder created for the new version.
I have written a powershell script to run in init.ps1 to pull the settings from the last version of the package, and seems to work. However this feels kinda dirty and I am wondering if there is a better way to solve this problem when using nuget to deliver my application.
param($installPath, $toolsPath, $package)
Set-Alias hump (Join-Path $toolsPath hump.exe)
$sorted_list = new-object system.collections.SortedList
$parent_path = Join-Path $installPath ".."
foreach($f in Get-ChildItem $parent_path -Filter Humpback* | Foreach {$_.FullName}){
$sorted_list.Add($f,$f)
}
if($sorted_list.Count -gt 1){
$old_path = $sorted_list.Values[$sorted_list.Count - 2]
$new_path = Join-Path $installPath "tools"
$current_settings = Join-Path $new_path "settings.js"
$has_current_settings = Test-Path $current_settings
if($has_current_settings -eq $false){
$old_settings = Join-Path $old_path "tools\settings.js"
Copy-Item $old_settings $new_path
}
}
Also, init.ps1 doesn't appear to run when installing a package using the command line tool (nuget.exe). Is this expected behavior?
Can you access System.Environment.GetFolderPath? I'd just create a folder under ApplicationData special folder, and store the settings there.

Power shell: Import-Module

I have been trying to us the app fabric caching on a win2008 standard server. When I execute the follwowing command I get:
Import-Module DistributedCacheAdministration
Import-Module : The specified module 'DistributedCacheAdministration' was not loaded because no valid module file was found in any module directory.
Where is this directory located and how can I use that module
Also, it appears that I have powershell 1. I cant seem to install powershell 2
Modules and their commands is a feature in Powershell 2 only, so you can be quite certain you're running this version. I guess you're confused because the Powershell.exe is located in a "1.0" directory; that's only to make version 2.0 backwards compatible.
You need to specify the exact location of the module to load: Import-Module [-Force] path-to-module-file`
Even better is have it available via the $PSModulePath environment variable. Try a Get-Module -ListAvailable to see what modules are available. Since the one you're trying to load does not seem to be listed, try setting the $PSModulePath to the folder above the directory holding the module file.
When you're satisfied with having the correct module path, set it via Computer Properties.
I installed AppFabric and the folder shows up at C:\Windows\System32\WindowsPowerShell\v1.0\Modules\DistributedCacheAdministration
Yet Import-Module DistributedCacheAdministration doesn't work and the module isn't listed in Get-Module -ListAvailable

Categories