How do I generate a self-signed certificate and use it to sign my powershell script? - powershell

So I've been researching/googling for the last 2 hours, and I'm practically at the point of tears...
I can't use New-SelfSignedCertificate because I'm on Windows 7.
I can't use makecert because of a bug that won't allow me to install the SDK for Windows 7 because it thinks I have a pre-release version of .NET 4, but I don't. Trying to install .NET 4 informed me I have a new or better version.
I tried a registry hack that I found to get around this, which unfortunately didn't work.
I've downloaded this
https://gallery.technet.microsoft.com/scriptcenter/Self-signed-certificate-5920a7c6#content
But can't seem to manage to get through all the steps I need to actually get my script signed so I can give it to other people to use safely.
I think I've managed to create the certificate (although I'm not sure if I did it right).
From what I can tell I need to apply a password or key to it now, and then export it? I'm still not sure how I specifically sign my script, so others can execute it as 'Signed'.
Thanks guys.
Alternatively all this could possibly be unnecessary if anyone knows how I can get relative .ps1 paths working in a .exe file?
The script works fine as a .ps1, but as soon as I compile it into a .exe using PowerGUI, these lines don't work.
. .\Import-XLS.ps1
$OutFile = ".\TEST$(get-date -Format dd-MM).txt"
$Content = Import-XLS '.\TEST.xlsx'
I instead get things like
"The term '.\Import-XLS.ps1' is not recognised as the name of a cmdlet, along with some reference to a Appdata\Local\Temp\QuestSoftware\PowerGUI\ folder.
So I'm guessing PowerGUI is doing something weird, but I don't know how else to convert a .ps1 into a .exe.
Depending on the answer to the main question, I may submit a new question for the .exe one officially.
Thanks guys.

So I ended up resolving this issue with a combination of two things.
Split-Path $MyInvocation.MyCommand.Path
and
[System.AppDomain]::CurrentDomain.BaseDirectory}
I needed to use both, as the former worked in a .ps1 but not in a compiled .exe, while the latter worked in a compiled .exe, but not in a .ps1.
As the PowerGUI compiled .exe has a consistent path folder name, I ended up using the following.
$ScriptPath = Split-Path $MyInvocation.MyCommand.Path
if ($ScriptPath -match 'Quest Software') {$ScriptPath = [System.AppDomain]::CurrentDomain.BaseDirectory}
I also included the Function into the .exe (but it wasn't necessary).
I then used $OutFile = "$ScriptPath\<Filename>.txt"
and $Content = Import-XLS "$ScriptPath\<Filename>.xlsx"
This means I can now use a .exe instead of trying to get a working certificate for the script. While also being able to quickly test changes to it while it's still a .ps1.
I hope this is helpful for others using PowerGUI to make .exe's in the future, who also need to use relative paths.
Thanks to those that provided help and advice.

So I have not used PowerGUI to create .exe files from scripts so this is a bit of a shot in the dark but I am guessing it just does not implement dot-sourcing external files, if that is the only thing preventing you from deploying the code why not just copy the functions from Import-XLS.ps1 into the body of your script?

Related

Changed Starting Path with PowerShell Profile But Cannot Change it Back

While learning Anaconda I had a problem with "cd" not working in Anaconda PowerShell, so I did what is recommended here, manually created a profile and set the path to a specific folder. It worked.
But today somehow I found "cd" is working for me again, so I was going to delete that ps1 file. But the folder together with the file in that was no loner there, completely gone. Now I am stuck with my temporary path on every PowerShell start-up.
According to Microsoft documentation, $profile should return my profile variables, which it did:
C:\Users\myname\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
But first, this is not the file name I gave it; second, this path is also non-existent, both folder and file.
I tried notepad $profile, then Notepad told me "The system cannot find the path specified." But it is exactly the path the system told me.
Some answer I saw here says that is because my profile is non-existent, I need to create one first. That is not the case here. I definitely overwrote my starting path, but I cannot find the actual profile file to edit that back.
I also tried doing it the same way again but changing "YOUR_FILE_PATH" into "%Home" hoping to "overwrite" it back, yet somehow this time it did not work and the file did not disappear as it did the first time.
I am really confused on this.
If you want to reset PowerShell to the original settings when PowerShell was installed.
Uninstall PowerShell from the Add or Remove Programs.
Restart your computer.
Reinstall PowerShell.

Powershell dot sourcing opens up file in notepad

Everytime i dot source a file in PowerShell it opens a copy of the file in notepad.
Exe:
.\MyScript.ps1
The script runs fine - its just really annoying having these pop up all the time. Is there a way to suppress this?
I'm on windows 7 x64 and using the latest version of PowerShell.
Ex2: This is still launching notepad.
cls
Set-Location "\\PSCWEBP00129\uploadedFiles\psDashboard\"
. .\assets\DCMPull\Powershell\SqlServerTransfer.psm1
. .\assets\DCMPull\Powershell\RunLogging.psm1
You cannot dot source PowerShell files with the .psm1 file extension. One option is to rename them to .ps1.
Alternatively (and, in my opinion the better approach), you can load the PowerShell modules using Import-Module <module.psm1>. Just note that the behavior of Import-Module is different from dot sourcing it. Dot sourcing runs the script in the current scope and also persists all variables, functions, etc.in the current scope. Import-Module does not do that.
Although not very common, you can also export variables from modules with Export-ModuleMember.
Adding to Raziel's answer, there's a lot of thought that went into only being able to dot source files with .ps1 extension, and otherwise why it tries to run it as a system executable. Here's a snippet from PeterWhittaker on GitHub:
. ./afile would only execute something if there's either an
extension-less but executable aFile in the current dir, or a
(not-required-to-be-executable) afile.ps1 file, with the former taking
precedence if both are present; if the file exists, but is neither
executable nor has extension .ps1, it is opened as if it were a
document.
. <filename> with <filename> being a mere name (no path component) by
(security-minded) design only ever looks for a file of that name in
the directories listed in $env:PATH (see below), not in the current
directory.
I encountered exactly the same situation : If the point source imports the .psm1 file, the file will be opened directly instead of importing the code in the file.
Because the function of point source import is only valid in the file with suffix of.ps1, if the suffix does not meet the requirements, it will not be regarded as path, but as a code , so it is like running the corresponding string directly, and the effect is naturally to open the file.
So,this phenomenon is not aimed at .PSM1,if you change the extension to TXT, it will have the same effect. It will have the same effect for any file whose suffix is not .PS1.
You can bypass this problem by creating symbolic links or hard links!
In PowerShell 7, it's easy to create links using New-Item.

PowerShell module changes not visible

I'm confused as to how PowerShell modules work.
I have downloaded and copied a module from a blogger. I've unblocked and extracted the .zip to %USERPROFILE%\Documents\WindowsPowerShell\Modules\SomeModule
In this folder is a .NET assembly that the module uses, but doesn't not contain compiled CmdLets. Instead, the commands are functions in a .psm1 file and a .psd1 file describes the manifest.
If I open PowerShell, the functions are available and work but I want to add my own function, so I have added it, however I cannot see it. I've restarted all PowerShell instances, removed the module and imported it again.
As a test, I renamed an existing, working function. Interestingly, after remove and import the function disappears instead of adopting its new name. If I rename it back (just a single character change) and remove/import then it appears again.
I use help blahblah to list all commands in a set, since they all have the same prefix. The manifest exports all (*) functions. Clearly I don't understand how these type of script modules work, the functions are all listed even after I run Remove-Module! I've written a compiled module before in C# and that worked as expected.
What's going on? Why does renaming a function cause it to vanish? Thanks.
Found it. This line appears in some stuff I overlooked in the .psm1 file.
Export-ModuleMember X, Y, Z
So, I guess the manifest can overrule this or replace the need for it in a script? Who knows. Anyway, hope this helps someone.

Using the nupack Package Manager Console to set working folder to solution folder

In Visual Studio, nupack adds a power-shell window called the Package Manager Console. I am thinking that this would be a good place to run source control commands (I'm using Mercurial). However, the default working directory is my users folder, so I need to navigate to my code folder every time I load a new project.
I am wondering if there is a one-line command to set the working directory to the solution folder. e.g. does something like this exist?
cd $SolutionFolder
From the results of get-variable it doens't look like there is anything immediately available, but I've never used powershell before, so maybe there is a way of getting the solution folder?
Thanks to Doug for pointing me in the right direction. I've written up full instructions on my blog here:
http://mark-dot-net.blogspot.com/2010/10/change-to-solution-folder-in-package.html
The basic answer is that the following command will do it:
Split-Path -parent $dte.Solution.FileName | cd
To make it more readily available, you need to create a function in your "user profile" script file, the location of which is found in the $profile variable. You will need to create the file if it doesn't exist. Then add a function:
Function solutionFolder()
{
Split-Path -parent $dte.Solution.FileName | cd
}
Now, after loading a solution in VS2010, you can simply type:
solutionFolder
and the working folder will be changed.
Try
$dte.Solution.FileName
I'm not sure when it changed, but the Package Manager Console automatically shifts the working directory to the current solution folder when you open an application now.

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).