Skip to content

Commit d26ec45

Browse files
authored
Merge pull request #5 from hbuckle/powershell6
Powershell core support
2 parents eaad16b + add7911 commit d26ec45

File tree

12 files changed

+185
-68
lines changed

12 files changed

+185
-68
lines changed

.rubocop.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Metrics/BlockLength:
1414
Max: 50
1515

1616
Metrics/LineLength:
17-
Max: 130
17+
Max: 135
1818

1919
EndOfLine:
2020
Enabled: false

Gemfile

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ gem 'metadata-json-lint'
66
gem 'puppet', puppetversion
77
gem 'puppet-lint', '>= 1.0.0'
88
gem 'puppetlabs_spec_helper', '>= 1.0.0'
9+
gem 'semantic_puppet', '>= 1.0.0'
910

1011
# rspec must be v2 for ruby 1.8.7
1112
if RUBY_VERSION >= '1.8.7' && RUBY_VERSION < '1.9'

README.md

+70-14
Original file line numberDiff line numberDiff line change
@@ -4,45 +4,101 @@
44

55
1. [Description](#description)
66
1. [Setup - The basics of getting started with powershellmodule](#setup)
7-
* [Setup requirements](#setup-requirements)
7+
* [Windows PowerShell](#windows-powershell)
8+
* [PowerShell Core](#powershell-core)
89
1. [Usage - Configuration options and additional functionality](#usage)
10+
* [Windows PowerShell](#windows-powershell)
11+
* [PowerShell Core](#powershell-core)
12+
* [Side by side installation](#side-by-side-installation)
913
1. [Limitations - OS compatibility, etc.](#limitations)
1014
1. [Development - Guide for contributing to the module](#development)
1115

1216
## Description
1317

14-
This module adds a new type and provider for registering PowerShell repositories
15-
and a new package provider for installing PowerShell modules.
18+
This module allows PowerShell repositories to be registered as package sources
19+
and PowerShell modules to be installed using the Puppet Package type.
20+
21+
The module supports Windows PowerShell (PowerShell 5) and PowerShell Core (PowerShell 6)
1622

1723
## Setup
1824

19-
### Setup Requirements
25+
### Windows PowerShell
2026

21-
The PowerShellGet PowerShell module must be installed as well as the NuGet package
22-
provider. PowerShellGet is included with WMF5 or can be installed for earlier
27+
For Windows PowerShell the PowerShellGet PowerShell module must be installed as well as
28+
the NuGet package provider. PowerShellGet is included with WMF5 or can be installed for earlier
2329
versions here http://go.microsoft.com/fwlink/?LinkID=746217&clcid=0x409
30+
2431
NuGet can be installed by running
25-
Install-PackageProvider Nuget –Force
2632

27-
### Beginning with powershellmodule
33+
`Install-PackageProvider Nuget –Force`
34+
35+
### PowerShell Core
36+
37+
PowerShellGet is included in PowerShell Core so no additional setup is necessary.
2838

2939
## Usage
3040

31-
~~~ puppet
41+
### Windows PowerShell
42+
43+
Windows users should remember that package names in Puppet are case sensitive.
44+
45+
```puppet
3246
psrepository { 'my-internal-repo':
3347
ensure => present,
3448
source_location => 'http://myrepo.corp.com/api/nuget/powershell',
3549
installation_policy => 'trusted',
50+
provider => 'windowspowershell',
3651
}
37-
~~~
52+
```
3853

39-
~~~ puppet
40-
package { 'pester':
54+
```puppet
55+
package { 'Pester':
4156
ensure => '4.0.3',
4257
source => 'PSGallery',
43-
provider => 'psmodule',
58+
provider => 'windowspowershell',
59+
}
60+
```
61+
62+
### PowerShell Core
63+
64+
```puppet
65+
psrepository { 'my-internal-repo':
66+
ensure => present,
67+
source_location => 'http://myrepo.corp.com/api/nuget/powershell',
68+
installation_policy => 'trusted',
69+
provider => 'powershellcore',
70+
}
71+
```
72+
73+
```puppet
74+
package { 'Pester':
75+
ensure => '4.0.3',
76+
source => 'PSGallery',
77+
provider => 'powershellcore',
78+
}
79+
```
80+
81+
### Side by side installation
82+
83+
On Windows, PowerShell Core is installed along side Windows PowerShell and maintains its
84+
modules separately. To install the same module for both versions then use a unique resource
85+
title and specify the `name` property.
86+
87+
```puppet
88+
package { 'PSExcel-wps':
89+
ensure => latest,
90+
name => 'PSExcel',
91+
provider => 'windowspowershell',
92+
source => 'PSGallery',
93+
}
94+
95+
package { 'PSExcel-psc':
96+
ensure => latest,
97+
name => 'PSExcel',
98+
provider => 'powershellcore',
99+
source => 'PSGallery',
44100
}
45-
~~~
101+
```
46102

47103
## Limitations
48104

examples/init.pp

+7-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@
1717

1818
package { 'PSExcel':
1919
ensure => latest,
20-
provider => 'psmodule',
20+
provider => 'windowspowershell',
2121
source => 'PSGallery',
2222
}
23+
24+
package { 'Pester':
25+
ensure => latest,
26+
provider => 'powershellcore',
27+
source => 'PSGallery',
28+
}

lib/puppet/feature/powershellget.rb lib/puppet/feature/powershellgetwindows.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
require 'puppet/util/feature'
22

3-
Puppet.features.add(:powershellget) do
3+
Puppet.features.add(:powershellgetwindows) do
44
command = '"Import-Module powershellget; $mod = Get-Module powershellget; $mod.Name"'
55
output = `powershell.exe -noprofile -executionpolicy bypass -command #{command}`
66
output.downcase.strip == 'powershellget'

lib/puppet/provider/package/psmodule.rb lib/puppet/provider/package/powershellcore.rb

+12-22
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,16 @@
11
require 'puppet/provider/package'
22
require 'json'
33

4-
Puppet::Type.type(:package).provide :psmodule, parent: Puppet::Provider::Package do
5-
confine operatingsystem: :windows
6-
confine feature: :powershellget
7-
8-
has_feature :installable
9-
has_feature :uninstallable
10-
has_feature :upgradeable
11-
has_feature :versionable
12-
13-
commands powershell:
14-
if File.exist?("#{ENV['SYSTEMROOT']}\\sysnative\\WindowsPowershell\\v1.0\\powershell.exe")
15-
"#{ENV['SYSTEMROOT']}\\sysnative\\WindowsPowershell\\v1.0\\powershell.exe"
16-
elsif File.exist?("#{ENV['SYSTEMROOT']}\\system32\\WindowsPowershell\\v1.0\\powershell.exe")
17-
"#{ENV['SYSTEMROOT']}\\system32\\WindowsPowershell\\v1.0\\powershell.exe"
18-
else
19-
'powershell.exe'
20-
end
4+
Puppet::Type.type(:package).provide :powershellcore, parent: Puppet::Provider::Package do
5+
initvars
6+
has_feature :installable, :uninstallable, :upgradeable, :versionable
7+
commands pwsh: 'pwsh'
218

229
def self.invoke_ps_command(command)
23-
result = powershell(['-noprofile', '-executionpolicy', 'bypass', '-command', command])
10+
# override_locale is necessary otherwise the Install-Module commands silently fails on Linux
11+
result = Puppet::Util::Execution.execute(['pwsh', '-NoProfile', '-NonInteractive', '-NoLogo', '-Command',
12+
"$ProgressPreference = 'SilentlyContinue'; $ErrorActionPreference = 'Stop'; #{command}"],
13+
override_locale: false)
2414
result.lines
2515
end
2616

@@ -62,15 +52,15 @@ def self.instances_command
6252
[ordered]@{
6353
'name' = $_.Name
6454
'ensure' = @(($_.Group).Version)
65-
'provider' = 'psmodule'
55+
'provider' = '#{name}'
6656
} | ConvertTo-Json -Depth 99 -Compress
6757
}
6858
COMMAND
6959
end
7060

7161
def install_command
72-
command = "Install-Module #{@resource[:name]} -Force"
73-
command << " -RequiredVersion #{@resource[:ensure]}" unless [:present, :latest].include? @resource[:ensure]
62+
command = "Install-Module #{@resource[:name]} -Scope AllUsers -Force"
63+
command << " -RequiredVersion #{@resource[:ensure]}" unless %i[present latest].include? @resource[:ensure]
7464
command << " -Repository #{@resource[:source]}" if @resource[:source]
7565
command
7666
end
@@ -84,7 +74,7 @@ def latest_command
8474
end
8575

8676
def update_command
87-
command = "Install-Module #{@resource[:name]} -Force"
77+
command = "Install-Module #{@resource[:name]} -Scope AllUsers -Force"
8878
command << " -Repository #{@resource[:source]}" if @resource[:source]
8979
command
9080
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
Puppet::Type.type(:package).provide(:windowspowershell, parent: :powershellcore) do
2+
initvars
3+
confine operatingsystem: :windows
4+
confine feature: :powershellgetwindows
5+
commands powershell: 'powershell'
6+
7+
def self.invoke_ps_command(command)
8+
result = powershell(['-NoProfile', '-ExecutionPolicy', 'Bypass', '-NonInteractive', '-NoLogo', '-Command',
9+
"$ProgressPreference = 'SilentlyContinue'; $ErrorActionPreference = 'Stop'; #{command}"])
10+
result.lines
11+
end
12+
end

lib/puppet/provider/psrepository/windows.rb lib/puppet/provider/psrepository/powershellcore.rb

+6-14
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,6 @@
1-
Puppet::Type.type(:psrepository).provide(:windows) do
2-
confine operatingsystem: :windows
3-
confine feature: :powershellget
4-
5-
commands powershell:
6-
if File.exist?("#{ENV['SYSTEMROOT']}\\sysnative\\WindowsPowershell\\v1.0\\powershell.exe")
7-
"#{ENV['SYSTEMROOT']}\\sysnative\\WindowsPowershell\\v1.0\\powershell.exe"
8-
elsif File.exist?("#{ENV['SYSTEMROOT']}\\system32\\WindowsPowershell\\v1.0\\powershell.exe")
9-
"#{ENV['SYSTEMROOT']}\\system32\\WindowsPowershell\\v1.0\\powershell.exe"
10-
else
11-
'powershell.exe'
12-
end
13-
1+
Puppet::Type.type(:psrepository).provide(:powershellcore) do
2+
initvars
3+
commands pwsh: 'pwsh'
144
mk_resource_methods
155

166
def initialize(value = {})
@@ -19,7 +9,9 @@ def initialize(value = {})
199
end
2010

2111
def self.invoke_ps_command(command)
22-
result = powershell(['-noprofile', '-executionpolicy', 'bypass', '-command', command])
12+
result = pwsh(['-NoProfile', '-NonInteractive', '-NoLogo', '-Command', "$ProgressPreference = 'SilentlyContinue'; #{command}"])
13+
Puppet.debug result.exitstatus
14+
Puppet.debug result.lines
2315
result.lines
2416
end
2517

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Puppet::Type.type(:psrepository).provide(:windowspowershell, parent: :powershellcore) do
2+
initvars
3+
confine operatingsystem: :windows
4+
confine feature: :powershellgetwindows
5+
commands powershell: 'powershell'
6+
7+
def self.invoke_ps_command(command)
8+
result = powershell(['-noprofile', '-executionpolicy', 'bypass', '-command', command])
9+
result.lines
10+
end
11+
end

metadata.json

+53-4
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
{
22
"name": "hbuckle-powershellmodule",
3-
"version": "0.2.0",
3+
"version": "1.0.0",
44
"author": "Henry Buckle",
55
"summary": "Manage PowerShell modules and repositories",
66
"license": "Apache-2.0",
77
"source": "https://github.com/hbuckle/puppet-powershellmodule",
88
"project_page": "https://github.com/hbuckle/puppet-powershellmodule",
99
"issues_url": "https://github.com/hbuckle/puppet-powershellmodule/issues",
10-
"tags": ["powershell", "microsoft", "package"],
10+
"tags": [
11+
"powershell",
12+
"microsoft",
13+
"package"
14+
],
1115
"dependencies": [],
1216
"operatingsystem_support": [
1317
{
@@ -22,7 +26,52 @@
2226
"8.1",
2327
"10"
2428
]
29+
},
30+
{
31+
"operatingsystem": "Debian",
32+
"operatingsystemrelease": [
33+
"8.7+",
34+
"9"
35+
]
36+
},
37+
{
38+
"operatingsystem": "CentOS",
39+
"operatingsystemrelease": [
40+
"7"
41+
]
42+
},
43+
{
44+
"operatingsystem": "Ubuntu",
45+
"operatingsystemrelease": [
46+
"14.04",
47+
"16.04",
48+
"17.04"
49+
]
50+
},
51+
{
52+
"operatingsystem": "RedHat",
53+
"operatingsystemrelease": [
54+
"7"
55+
]
56+
},
57+
{
58+
"operatingsystem": "Fedora",
59+
"operatingsystemrelease": [
60+
"25",
61+
"26"
62+
]
63+
},
64+
{
65+
"operatingsystem": "openSUSE",
66+
"operatingsystemrelease": [
67+
"42.2"
68+
]
69+
},
70+
{
71+
"operatingsystem": "OSX",
72+
"operatingsystemrelease": [
73+
"10.12+"
74+
]
2575
}
2676
]
27-
}
28-
77+
}

spec/unit/puppet/provider/psmodule_spec.rb

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
require 'spec_helper'
22

3-
provider_class = Puppet::Type.type(:package).provider(:psmodule)
3+
provider_class = Puppet::Type.type(:package).provider(:windowspowershell)
44

55
describe provider_class do
66
before(:each) do
@@ -11,14 +11,14 @@
1111
allow(provider_class).to receive(:invoke_ps_command).with(
1212
provider_class.instances_command).and_return(
1313
[
14-
'{"name":"PackageManagement","ensure":["1.1.6.0","1.1.7.0"],"provider":"psmodule"}',
15-
'{"name":"Pester","ensure":["4.0.8"],"provider":"psmodule"}',
16-
'{"name":"PowerShellGet","ensure":["1.5.0.0"],"provider":"psmodule"}'
14+
'{"name":"PackageManagement","ensure":["1.1.6.0","1.1.7.0"],"provider":"windowspowershell"}',
15+
'{"name":"Pester","ensure":["4.0.8"],"provider":"windowspowershell"}',
16+
'{"name":"PowerShellGet","ensure":["1.5.0.0"],"provider":"windowspowershell"}'
1717
]
1818
)
1919
end
2020
describe :instances do
21-
specify 'returns an array of :psmodule providers' do
21+
specify 'returns an array of :windowspowershell providers' do
2222
instances = provider_class.instances
2323
expect(instances.count).to eq(3)
2424
expect(instances).to all(be_instance_of(provider_class))

0 commit comments

Comments
 (0)