Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Request] Provide quick way to sign PS scripts with the extension #548

Open
squawkingVFR opened this issue Mar 15, 2017 · 17 comments
Open
Milestone

Comments

@squawkingVFR
Copy link

@squawkingVFR squawkingVFR commented Mar 15, 2017

System Details

  • Operating system name and version: Windows 10 1607
  • VS Code version: 1.10.2
  • PowerShell extension version: 0.10.0

Issue Description

I am experiencing a problem with...

Attached Logs

Follow the instructions in the README
about capturing and sending logs.

@daviwil daviwil modified the milestones: 0.12.0, Backlog Mar 15, 2017
@daviwil

This comment has been minimized.

Copy link
Collaborator

@daviwil daviwil commented Mar 15, 2017

Could be a helpful task, we'll look into it.

@daviwil

This comment has been minimized.

Copy link
Collaborator

@daviwil daviwil commented May 31, 2017

/cc @dotps1 @daGup

So how do you normally sign your scripts, something like this?

$cert = dir cert:currentuser\my\ -CodeSigningCert | select -First 1
$timeStampUrl = "some url"
Set-AuthenticodeSignature ScriptPath.ps1 -IncludeChain All -TimeStampServer $timeStampURL

I could pretty easily expose a task for signing the current script with some configuration parameters to set the cert path, timeStampUrl, etc. I could also try to auto-sign scripts before running them in the debugger. Would that be helpful?

@daviwil daviwil modified the milestones: June 2017, Backlog May 31, 2017
@daGup

This comment has been minimized.

Copy link

@daGup daGup commented May 31, 2017

@daviwil

This comment has been minimized.

Copy link
Collaborator

@daviwil daviwil commented May 31, 2017

Which specific parameters do you use on Set-AuthenticodeSignature? Do you use -IncludeChain All or just the Path and TimeStampServer parameters?

@daGup

This comment has been minimized.

Copy link

@daGup daGup commented Jun 1, 2017

@daviwil

This comment has been minimized.

Copy link
Collaborator

@daviwil daviwil commented Jun 1, 2017

Yep, it's possible to make those configurable.

@rkeithhill

This comment has been minimized.

Copy link
Collaborator

@rkeithhill rkeithhill commented Jun 1, 2017

@daGup I'm curious if you would you prefer a mini-build/release process that does the script signing for you - kind of like the task you were trying to set up?

One issue with signing scripts is that you often don't want to sign the "original" script especially if it is checked into source control. It's much easier to develop & debug against a unsigned script and then sign the script when you're ready to release it. And if you ever put your source up on something like GitHub, you don't want the checked in script(s) to be signed since folks who fork your repo won't have your code-signing cert.

Ideally, I'd like to see a build system that could be configured to do as little or as much as you need. Something where perhaps all you need to do to get your script(s) signed is to fill out a few settings in a file (build.settings.ps1) e.g.:

    # ----------------------- Basic properties --------------------------------

    # The root directory containing scripts to process
    $SrcRootDir  = "$PSScriptRoot"

    # ------------------- Script signing properties ---------------------------

    # Set to $true if you want to sign your scripts. You will need to have a code-signing certificate.
    # You can specify the certificate's subject name below. If not specified, you will be prompted to
    # provide either a subject name or path to a PFX file.  After this one time prompt, the value will
    # saved for future use and you will no longer be prompted.
    [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')]
    $ScriptSigningEnabled = $false

    # Specify the Subject Name of the certificate used to sign your scripts.  Leave it as $null and the
    # first time you build, you will be prompted to enter your code-signing certificate's Subject Name.
    # This variable is used only if $SignScripts is set to $true.
    #
    # This does require the code-signing certificate to be installed to your certificate store.  If you
    # have a code-signing certificate in a PFX file, install the certificate to your certificate store
    # with the command below. You may be prompted for the certificate's password.
    #
    # Import-PfxCertificate -FilePath .\myCodeSigingCert.pfx -CertStoreLocation Cert:\CurrentUser\My
    #
    [System.Diagnostics.CodeAnalysis.SuppressMessage('PSUseDeclaredVarsMoreThanAssigments', '')]
    $CertSubjectName = $null

Then press Ctrl+Shift+B and the build copies your scripts to another folder (release or out) where they get signed.

@daGup

This comment has been minimized.

Copy link

@daGup daGup commented Jun 1, 2017

@olathemike

This comment has been minimized.

Copy link

@olathemike olathemike commented Jul 10, 2017

I am not clear on where this stands, but I think code signing is becoming a big deal and will continue to increase in importance over time. We are now white-listing our scripts and exes and we have a choice between getting the chksum for each item we want to allow to run and entering that into the white listing tool (ouch), or using signed code (everything signed with one of a few certificates). I really prefer the editor and capabilities of VS Code, but debugging is tough when you can't setup a sign on save.

@rkeithhill

This comment has been minimized.

Copy link
Collaborator

@rkeithhill rkeithhill commented Jul 10, 2017

I'm not opposed to putting this functionality into the VSCode PowerShell extension. I just think that most folks would find an extension provided mechanism rather limiting. OTOH when built into their build process can they customize to fit their particular needs.

You can use VSCode's task runner to kick off a build using either psake or InvokeBuild. That build process can do various things including copying your source into an output folder where it can be signed and can be easily .gitignored. You don't develop/commit signed source, do you?

Then you can setup a debug config to debug the signed scripts from the output folder. This is something you can do today without waiting on the extension to add such a feature. Here's a very simple psake script - build.ps1 (not tested but should give you the idea):

Properties {
    $OutDir = "$PSScriptRoot\out"
}

Task default -depends Build

Task Build -depends Init, Clean, Sign {}

Task Init -requiredVariables OutDir {
    if (!(Test-Path $OutDir)) {
        $null = New-Item $OutDir -ItemType Directory
    }
}

Task Clean -requiredVariables OutDir {
    if (Test-Path $OutDir) {
        Remove-Item $OutDir\* -Recurse -Force
    }
}

Task Sign -requiredVariables OutDir {
    # Modify this line to copy your scripts into the out dir
    Copy-Item $PSScriptRoot\src\* $OutDir -Recurse

    # Grab your cert and sign the scripts in the out dir.
    $cert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert | 
        Where-Object Subject -match CompanyNane | 
        Sort-Object NotAfter -Descending | Select -First 1
    foreach ($script in (Get-ChildItem $OutDir -File *.ps*1)) {
        Set-AuthenticodeSignature -LiteralPath $script.FullName -Cert $cert
    }
}

Install psake with Install-Module psake -Scope CurrentUser.
Then configure your .vscode\tasks.json file like so:

{
    "version": "2.0.0",

    // Start PowerShell
    "windows": {
        "command": "${env:windir}\\sysnative\\WindowsPowerShell\\v1.0\\powershell.exe",
        "args": [ "-NoProfile", "-ExecutionPolicy", "Bypass" ]
    },
    "linux": {
        "command": "/usr/bin/powershell",
        "args": [ "-NoProfile" ]
    },
    "osx": {
        "command": "/usr/local/bin/powershell",
        "args": [ "-NoProfile" ]
    },

    // Show the output window always
    "showOutput": "always",

    // Associate with test task runner
    "tasks": [
        {
            "taskName": "Clean",
            "suppressTaskName": true,
            "showOutput": "always",
            "args": [
                "Write-Host 'Invoking PSake...'; Invoke-PSake build.ps1 -taskList Clean;",
                "Invoke-Command { Write-Host 'Completed Clean task in task runner.' }"
            ]
        },
        {
            "taskName": "Build",
            "suppressTaskName": true,
            "isBuildCommand": true,
            "showOutput": "always",
            "args": [
                "Write-Host 'Invoking PSake...'; Invoke-PSake build.ps1 -taskList Build;",
                "Invoke-Command { Write-Host 'Completed Build task in task runner.' }"
            ]
        }
        {
            "taskName": "Test",
            "suppressTaskName": true,
            "isTestCommand": true,
            "showOutput": "always",
            "args": [
                "Write-Host 'Invoking Pester...'; Invoke-Pester -PesterOption @{IncludeVSCodeMarker=$true};",
                "Invoke-Command { Write-Host 'Completed Test task in task runner.' }"
            ],
            "problemMatcher": "$pester"
        }
    ]
}

You should be able to "build" with a press of Ctrl+Shift+B. Then set up your debug config to launch a script from the out dir.

Of, if you are using Git, add out (or whatever you call it) to your .gitignore file.

@daviwil daviwil modified the milestones: June 2017, July 2017 Jul 11, 2017
@olathemike

This comment has been minimized.

Copy link

@olathemike olathemike commented Jul 11, 2017

@daviwil daviwil modified the milestones: July 2017, Future Oct 26, 2017
@kensel

This comment has been minimized.

Copy link

@kensel kensel commented Dec 30, 2017

If the signing can be added to the tasks.json and be able to run on the script real quickly as I use VS Code to edit ps1 files exclusively and they aren't necessarily all in a git repo. I think it would be useful to provide a quick ctrl + shift + P or other hot key and then document a more extensive build process. This way quick edits to files that aren't in a structured format could be signed quickly and there is a process for more detailed build processes.

I don't use the build process enough to know the best ways to set it up and all the ways to pass stuff through. Like can the user settings be passed to the build process for example having a cert thumbprint (or other identifier) be saved in the settings to be passed to build task for the command to use?

I have also updated the tasks.json from above with the current formatting details from reading the intellisense popup.

{
    // See https://go.microsoft.com/fwlink/?LinkId=733558`
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    // Start PowerShell
    "windows": {
        "command": "${env:windir}\\sysnative\\WindowsPowerShell\\v1.0\\powershell.exe",
        "args": [ "-NoProfile", "-ExecutionPolicy", "Bypass" ]
    },
    "linux": {
        "command": "/usr/bin/powershell",
        "args": [ "-NoProfile" ]
    },
    "osx": {
        "command": "/usr/local/bin/powershell",
        "args": [ "-NoProfile" ]
    },
    // Show the output window always
    "showOutput": "always",
    // Associate with test task runner
    "tasks": [
        {
            "label": "Clean",
            "group":  "none",
            "presentation": {
                "echo": true,
                "reveal": "always",
                "focus": false,
                "panel": "shared"
            },
            "args": [
                "Write-Host 'Invoking PSake...'; Invoke-PSake build.ps1 -taskList Clean;",
                "Invoke-Command { Write-Host 'Completed Clean task in task runner.' }"
            ]
        },
        {
            "label": "Build",
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "presentation": {
                "echo": true,
                "reveal": "always",
                "focus": false,
                "panel": "shared"
            },
            "args": [
                "Write-Host 'Invoking PSake...'; Invoke-PSake build.ps1 -taskList Build;",
                "Invoke-Command { Write-Host 'Completed Build task in task runner.' }"
            ]
        },
        {
            "label": "Test",
            "group": {
                "kind": "test",
                "isDefault": true
            },
            "presentation": {
                "echo": true,
                "reveal": "always",
                "focus": false,
                "panel": "shared"
            },
            "args": [
                "Write-Host 'Invoking Pester...'; Invoke-Pester -PesterOption @{IncludeVSCodeMarker=$true};",
                "Invoke-Command { Write-Host 'Completed Test task in task runner.' }"
            ],
            "problemMatcher": "$pester"
        }
    ]
}
@rkeithhill

This comment has been minimized.

Copy link
Collaborator

@rkeithhill rkeithhill commented Dec 31, 2017

@kensel That tasks.json is a bit out-of-date (still uses sysnative & powershell instead of pwsh on Linux/OSX). See this one which is up-to-date: https://github.com/PowerShell/vscode-powershell/blob/master/examples/.vscode/tasks.json

You can easily add a task to sign the active file. It requires that you encode a way to locate the code-signing cert that you want to use e.g.:

        {
            "label": "Sign",
            "type": "shell",
            "command": "$subject = 'your cert subject name'; $cert = @(Get-ChildItem Cert:/CurrentUser -Recurse -CodeSigningCert | Where-Object Subject -match $subject | Where-Object NotAfter -gt (Get-Date)); Set-AuthenticodeSignature ${file} $cert[0]"
        },

BTW the issue with sysnative is that the more popular version of VSCode is 64-bit and sysnative isn't recognized in a 64-bit process.

@TylerLeonhardt

This comment has been minimized.

Copy link
Member

@TylerLeonhardt TylerLeonhardt commented Feb 21, 2018

@rkeithhill do you think we should add such a task to the tasks.json?

@rkeithhill

This comment has been minimized.

Copy link
Collaborator

@rkeithhill rkeithhill commented Feb 21, 2018

The problem with the task is it requires input/modification. It requires info to pick a code signing cert when there is more than one on the machine. That is pretty common for my machines.

If we made this an extension command, we could present a pick list of code-signing certs if we find more than one valid code-signing cert.

@TylerLeonhardt TylerLeonhardt modified the milestone: Future May 24, 2018
@TylerLeonhardt TylerLeonhardt modified the milestone: Future May 24, 2018
@fullenw1

This comment has been minimized.

Copy link
Contributor

@fullenw1 fullenw1 commented Nov 25, 2019

Is somebody still working on this feature request? :)

@TylerLeonhardt

This comment has been minimized.

Copy link
Member

@TylerLeonhardt TylerLeonhardt commented Nov 25, 2019

Not a high priority for the PowerShell team at the moment - too busy on performance & stability.

However, we're open source so if you're interested in contributing, we'd love to work with you! Although we should understand what scenario we are specifically targeting here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
8 participants
You can’t perform that action at this time.