PowerShell dependency management - deployment

Scenario
My PowerShell folder contains a library of utility scripts. I have it shared and version controlled with GitHub between my work and home computers. At work I now have a number of projects where I want to take advantage of my script library.
Problem
When I update the a utility script, I don't want to copy it manually to all the work projects where it is used.
Possible solutions
(Simple)
Write a PowerShell function to copy my whole script library to a 'Dependencies\Scripts' directory under the working directory for each script project. As my script library grows, it may become difficult for others to find the library scripts that are relevant to the script project.
(Overcomplicated?)
Use some kind of 'requires' function in each work project script file that requires one of library scripts. When a library script is updated a tool can then decide which work projects require that library script and copy the latest version to the work project. If a script is run without the appropriate dependency it will throw an error that reminding the user how to get the latest version from the library.
Questions
Has anyone solved this problem before?
Are there existing dependency management tools for PowerShell that will do 2?

Have you considered NuGet? It supports package dependencies, updates, and private repositories.
See also: Use Nuget to Share PowerShell Modules in your Enterprise

I created a solution for you that I think will fit your situation. I created it based off of the song playlist methodology. I created an xml document where you would list each of your scripts individually and in another node in the same document you list the scripts you want to copy for each project. I have created a working example of this below. Though it is not elegant when it comes to managing a few hundred script files or alot of projects but it gets the job done.
PS1 Script
[xml]$XML = gc "C:\XMLFile1.xml"
$Scripts = $XML.Root.Scripts.Script
$Projects = $XML.Root.Projects.Project
foreach($Project in $Projects){
$ProjectLocation = $Project.CopyPath
$ProjectScripts = $Project.Script
foreach($Script in $ProjectScripts){
$ScriptPath = ($Scripts|?{$_.ID -eq $Script.ID}|Select Path).Path
Copy-Item -Path $ScriptPath -Destination $ProjectLocation
}
}
XMLFile
<Root>
<Scripts>
<Script ID="1" Path="C:\1.PS1"></Script>
<Script ID="2" Path="C:\2.PS1"></Script>
<Script ID="3" Path="C:\3.PSM1"></Script>
</Scripts>
<Projects>
<Project Name="Project1" CopyPath="\\Server\Share\Project1">
<Scripts ID="1"/>
</Project>
<Project Name="Project2" CopyPath="C:\Projects\Project2">
<Scripts ID="1"/>
<Scripts ID="3"/>
</Project>
</Projects>
</Root>

A simple solution would be to use something like DropBox. You can see how I use it for my PowerShell Scripts here: http://www.ravichaganti.com/blog/?p=1963
You can get a DropBox account with 2GB of free space http://db.tt/1DID1mR. 2GB, in my opinion, is more than enough for simple scripts. There are also other choices in the market. However, I recommend DropBox. The free account supports restoring 30 days old file versions.

Related

Loading/use CsvHelper in PowerShell 7/.NET 5

Long story short - requesting assistance loading/using CsvHelper in PS 7 w/.NET 5. Dll loads fine but no exported commands available. Added a manifest (nested, root, etc) with full export didn't expose. Assistance would be greatly appreciated.
Long story long - Have a system with fairly vanilla installs of pwsh v7.1.3 and .NET v5.0.300. I've been assigned a project to work with very large CSV files and process them with SQLBULKCOPY. The files will have formatting challenges as well as date (datetime2) fun so a Csv parser seems to be the best course of action.
After seeing that CsvHelper can cut through the parsing requirements, is compiled for .NET 5 (no dependencies), and reading reviews showing 20%+ better performance than another DLL (lu...) being tested I would like to leverage it for the project.
This solution will be used on systems with no access to the internet and users with limited skills, so the hope is to use just include the CsvHelper dll in the script module directory.
Loading the CsvHelper.dll (net5.0) file import-module "...\CsvHelper.dll" appears to work. Get-Module shows the dll is loaded but doesn't show any exported commands. Get-Command doesn't either. I've tried creating a manifest file for the DLL (nestedmodules, rootmodule, etc. and export specific publics, *) but am unsuccessful. I'm sure I'm missing something simple and would appreciate assistance. Thanks much.
When I started this project the first test was using a Lumenworks parser. It can be loaded into PS and used directly. That was nice and it set my head in that specific direction. Moving into CsvHelper I was wanting (hoping) to stay in PS only. There were bureaucratic motivations to not to go into studio, compile a dll, and the like.
My hope was to load the helper dll in PS and then inline the C# code. Something along the lines of:
Import-Module "C:\...\CsvHelper.dll"
or
$Assem = (
<?? for csvhelper>
)
with
$source = #"
using CsvHelper;
<C# around using CsvHelper>
"#
and appropriate Add-Type
Add-Type -ReferencedAssemblies $Assem -TypeDefinition $Source -Language CSharp
What I wanted to do can probably be done but I don't have the skills for it. For now I'm going with a Studio project. Will build set it to do what I want, use it in PS for the solution and deal with the politics.
Appreciate the inputs.

VS2015: recursively adding external content directories to AppX

I try to add a folder and its subfolders (~4000 files) as content to a C++ windows store app (in VS2015).
Heres the scenario:
G:\Game -> is the build directory
D:\data -> holds the original content
I've read there are some methods to declare external content in the .vxcproj file like that:
<ItemGroup>
<Content Include="D:\**">
<Link>%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<DeploymentContent>true</DeploymentContent>
</Content>
</ItemGroup>
This actually copies the contents of D:\data into the build-directory (G:\Game). This is great since the program can now be run & debugged. BUT: as soon as i deploy the project to the AppX Folder (G:\Game\AppX) the data-folder doesnt get deployed there.
G:\Game\game.exe
G:\Game\data\...
G:\Game\AppX
G:\Game\AppX\game.exe
(G:\Game\AppX\data\... - missing)
Any clues ?
After fiddling around for days, as of now i can state there is no way to do this properly in the Visual C++ - IDE (2012 / 2015) (it seemed to work with C# projects though).
The only way to achieve what i wanted to do is
a post-build-event using robocopy to copy/synch the data over to the AppX folder
Writing a script for the packaging / signing using MakeAppX.exe, SignTool.exe and 7-zip.

How to set nuget package version using build number with nugetter

We're using nugetter to make a nupkg as part of our build process for a solution that only builds occasionally, and that we want to distribute in the future. We also want to use this package in other solutions we have. So far, I've been able to generate a package that we can install. Now, I want to be sure that this package updates its version every time it's built so we can update the package easily. I'm thinking that using the build number would be a good way to do this, but I'd be willing to use just about any incrementing scheme if I don't have to start writing a powershell script to update the nuspec for package on every build.
Is there a way to do this automatically in nugetter?
If not, is there something easier than modifying the nuspec with powershell?
We're trying to do the same thing. NuGetter ships with a build process template that builds on top of TfsVersioning. Are you using that already? If so, all you have to do is add a special element for your NuGet package ID to the VersionSeed.xml file.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<VersionSeed>
<Solution name="Your Solution Name">
<!-- This is the pattern used to replace the AssemblyVersion value. -->
<AssemblyFileVersionPattern>1.0.J.B</AssemblyFileVersionPattern>
<!-- This is the pattern used to replace the AssemblyVersion value. -->
<AssemblyVersionPattern>1.0.0.0</AssemblyVersionPattern>
</Solution>
<NuGetPackage id="Your NuGet Package ID">
<!-- This is the pattern used to replace the version attribute in the NuSpec file. -->
<VersionPattern>1.0.J.B</VersionPattern>
</NuGetPackage>
</VersionSeed>
It's not a very well documented NuGetter feature, but it's in their help file somewhere.
Also, you still have to set the <version> attribute in the NuSpec file. Currently, I force it to 0.0.0.0 because it is overridden by the build process anyway. Removing the <version> element completely seems to always result in a crash.

Environment.CurrentDirectory with NUnit GUI differs to the TeamCity value, how can I sync them?

As above really, I have some integration tests that use files from a relative file path. To help picture it here is the file structure:
/Dependencies
/VideoTests/bin/release/video.dll
/SearchTests/bin/release/search.dll
/OtherProjects
The GUI is running the tests from the root, however when TeamCity runs the tests it is running the tests from each test dlls bin directory. Now I don't mind which one I can get to follow the other but I do need them to be the same otherwise my relative paths just won't work!
Any ideas?
P.S. Using TeamCity 5.0 and NUnit 2.5.
You probably don't want to rely on CurrentDirectory. I'd suggest reading the doc, but the main point you'll want to take away is that the CurrentDirectory is where the .exe was started from: it could be any path in the system. For example, let's assume your users add your .exe (or whatever .exe uses your DLLs) to their path. They could then navigate to c:\foo\bar and start the .exe from there, which would set the CurrentDirectory to "C:\foo\bar" and you may not be able to deal with that.
I think it would be preferable for you to rework whatever you're doing so you don't rely on CurrentDirectory. What problems are you encountering by relying on CurrentDirectory right now?
Have you made sure that both TeamCity and NUnit are using the same working directory when starting the application?
And if they aren't, you could adjust the current directory in the test code.

PowerShell App.Config

Has anyone worked out how to get PowerShell to use app.config files? I have a couple of .NET DLL's I'd like to use in one of my scripts but they expect their own config sections to be present in app.config/web.config.
Cross-referencing with this thread, which helped me with the same question:
Subsonic Access To App.Config Connection Strings From Referenced DLL in Powershell Script
I added the following to my script, before invoking the DLL that needs config settings, where $configpath is the location of the file I want to load:
[appdomain]::CurrentDomain.SetData("APP_CONFIG_FILE", $configpath)
Add-Type -AssemblyName System.Configuration
See this post to ensure the configuration file specified is applied to the running context.
I'm guessing that the settings would have to be in powershell.exe.config in the powershell directory, but that seems to be a bad way of doing things.
You can use ConfigurationManager.OpenMappedExeConfiguration to open a configuration file based on the executing DLL name, rather than the application exe, but this would obviously require changes to the DLLs.
Attempting a new answer to an old question.
I think the modern answer would be: don't do that. PowerShell is a shell. The normal way of passing information between parts of the shell are shell variables. For powershell that would look like:
$global:MyComponent_MySetting = '12'
# i.e.
$PSDefaultParameterValues
$ErrorActionPreference
If settings is expected to be inherited across processes boundaries the convention is to use environment variables. I extend this to settings that cross C# / PowerShell boundary. A couple of examples:
$env:PATH
$env:PSModulePath
If you think this is an anti-pattern for .NET you might want to reconsider. This is the norm for PAAS hosted apps, and is going to be the new default for ASP.NET running on server-optimized CLR (ASP.NET v5).
See https://github.com/JabbR/JabbRv2/blob/dev/src/JabbR/Startup.cs#L21
Note: at time of writing I'm linking to .AddEnvironmentVariables()
I've revisited this question a few times, including asking it myself. I wanted to put a stake in the ground to say PowerShell stuff doesn't work well with <appSettings>. IMO it is much better to embrace the shell aspect of PS over the .NET aspect in this regards.
If you need complex configuration take a JSON string. POSH v3+ has ConvertFrom-JSON built-in. If everything in your process uses the same complex configuration put it in a .json file and point to that file from an environment variable.
If a single file doesn't suffice there are well established solutions like the PATH pattern, GIT .gitignore resolution, or ASP.NET web.config resolution (which I won't repeat here).