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

Use all-in-one ms_dotnet cookbook #61

Merged
merged 6 commits into from Dec 11, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 1 addition & 3 deletions README.md
Expand Up @@ -72,9 +72,7 @@ Not every version of Windows supports every version of Powershell. The following

PowerShell also requires the appropriate version of the Microsoft .NET Framework to be installed, if the operating system does not ship with that version. The following community cookbooks are used to install the correct version of the .NET Framework:

* ms_dotnet2
* ms_dotnet4
* ms_dotnet45
* ms_dotnet

Resource/Provider
-----------------
Expand Down
4 changes: 1 addition & 3 deletions metadata.rb
Expand Up @@ -16,9 +16,7 @@

supports 'windows'
depends 'windows', '>= 1.2.8'
depends 'ms_dotnet45'
depends 'ms_dotnet4'
depends 'ms_dotnet2'
depends 'ms_dotnet', '>= 2.6'
depends 'chef_handler'

source_url 'https://github.com/chef-cookbooks/powershell' if respond_to?(:source_url)
Expand Down
40 changes: 11 additions & 29 deletions recipes/powershell2.rb
Expand Up @@ -23,48 +23,30 @@

case node['platform']
when 'windows'
nt_version = ::Windows::VersionHelper.nt_version(node)

require 'chef/win32/version'
windows_version = Chef::ReservedNames::Win32::Version.new
include_recipe 'ms_dotnet::ms_dotnet2'

if (windows_version.windows_server_2012? || windows_version.windows_8?) && windows_version.core?
# Windows Server 2012 Core does not come with Powershell 2.0 enabled
if nt_version.between?(6.1, 6.2) && ::Windows::VersionHelper.core_version?(node)
feature_suffix = 'V2' if nt_version == 6.2

windows_feature 'MicrosoftWindowsPowerShellV2' do
windows_feature "MicrosoftWindowsPowerShell#{feature_suffix}" do
action :install
end
windows_feature 'MicrosoftWindowsPowerShellV2-WOW64' do
action :install
only_if { node['kernel']['machine'] == 'x86_64' }
end

elsif (windows_version.windows_server_2008_r2? || windows_version.windows_7?) && windows_version.core?
# Windows Server 2008 R2 Core does not come with .NET or Powershell 2.0 enabled

windows_feature 'NetFx2-ServerCore' do
action :install
end
windows_feature 'NetFx2-ServerCore-WOW64' do
windows_feature "MicrosoftWindowsPowerShell#{feature_suffix}-WOW64" do
action :install
only_if { node['kernel']['machine'] == 'x86_64' }
end
windows_feature 'MicrosoftWindowsPowerShell' do
action :install
end
windows_feature 'MicrosoftWindowsPowerShell-WOW64' do
action :install
only_if { node['kernel']['machine'] == 'x86_64' }
end

elsif windows_version.windows_server_2008? || windows_version.windows_server_2003_r2? ||
windows_version.windows_server_2003? || windows_version.windows_xp?

include_recipe 'ms_dotnet2'

# WMF 2.0 is required and only compatible with:
# * Windows NT 5.1 & 5.2 (Windows Server 2003 & Windows XP)
# * Windows NT 6.0 server (Windows Server 2008 SP2 not vista)
elsif nt_version.between?(5.1, 5.2) || (nt_version == 6.0 && ::Windows::VersionHelper.server_version?(node))
# Reboot if user specifies doesn't specify no_reboot
include_recipe 'powershell::windows_reboot' unless node['powershell']['installation_reboot_mode'] == 'no_reboot'

windows_package 'Windows Management Framework Core' do
windows_package 'Windows Management Framework Core' do # ~FC009
source node['powershell']['powershell2']['url']
checksum node['powershell']['powershell2']['checksum']
installer_type :custom
Expand Down
14 changes: 8 additions & 6 deletions recipes/powershell3.rb
Expand Up @@ -24,13 +24,15 @@
case node['platform']
when 'windows'

require 'chef/win32/version'
windows_version = Chef::ReservedNames::Win32::Version.new
nt_version = ::Windows::VersionHelper.nt_version(node)

if windows_version.windows_server_2008? || windows_version.windows_server_2008_r2? || windows_version.windows_7?
# Powershell 3.0 is only compatible with:
# * Windows NT 6.0 server (Windows Server 2008 SP2 not vista)
# * Windows NT 6.1 (Windows Server 2008R2 & Windows 7.1)
if (nt_version == 6.0 && ::Windows::VersionHelper.server_version?(node)) || nt_version == 6.1

# For Windows Server 2008 ensure that Powershell 2 is already installed and so is BITS 4.0
if windows_version.windows_server_2008?
if nt_version == 6.0 && ::Windows::VersionHelper.server_version?(node)
include_recipe 'powershell::powershell2'

windows_package 'Windows Management Framework Bits' do
Expand All @@ -43,12 +45,12 @@
end

# WMF 3.0 requires .NET 4.0
include_recipe 'ms_dotnet4'
include_recipe 'ms_dotnet::ms_dotnet4'

# Reboot if user specifies doesn't specify no_reboot
include_recipe 'powershell::windows_reboot' unless node['powershell']['installation_reboot_mode'] == 'no_reboot'

windows_package 'Windows Management Framework Core 3.0' do
windows_package 'Windows Management Framework Core 3.0' do # ~FC009
source node['powershell']['powershell3']['url']
checksum node['powershell']['powershell3']['checksum']
installer_type :custom
Expand Down
15 changes: 9 additions & 6 deletions recipes/powershell4.rb
Expand Up @@ -22,18 +22,21 @@
# http://www.microsoft.com/en-us/download/details.aspx?id=40855

if node['platform'] == 'windows'
require 'chef/win32/version'
windows_version = Chef::ReservedNames::Win32::Version.new

if windows_version.windows_server_2008_r2? || windows_version.windows_7? || windows_version.windows_server_2012?
nt_version = ::Windows::VersionHelper.nt_version(node)
# WMF 4.0 is only compatible with:
# * Windows NT 6.1 (Windows Server 2008R2 & Windows 7.1)
# * Windows NT 6.2 Server (Windows Server 2012 not Windows 8)
if nt_version == 6.1 || (nt_version == 6.2 && ::Windows::VersionHelper.server_version?(node))

# Ensure .NET 4.5 is installed or installation will fail silently per Microsoft. Only necessary for Windows 2008R2 or 7.
include_recipe 'ms_dotnet45' if windows_version.windows_server_2008_r2? || windows_version.windows_7?
# Ensure .NET 4.5 is installed or installation will fail silently per Microsoft.
fail 'Attribute ms_dotnet.v4.version is not configured to install .NET4.5 as required for Powershell4' if node['ms_dotnet']['v4']['version'] < '4.5'
include_recipe 'ms_dotnet::ms_dotnet4'

# Reboot if user specifies doesn't specify no_reboot
include_recipe 'powershell::windows_reboot' unless node['powershell']['installation_reboot_mode'] == 'no_reboot'

windows_package 'Windows Management Framework Core4.0' do
windows_package 'Windows Management Framework Core 4.0' do # ~FC009
source node['powershell']['powershell4']['url']
checksum node['powershell']['powershell4']['checksum']
installer_type :custom
Expand Down
11 changes: 4 additions & 7 deletions recipes/powershell5.rb
Expand Up @@ -21,19 +21,16 @@
# PowerShell 5.0 Preview Download Page
# http://www.microsoft.com/en-us/download/details.aspx?id=42316

include_recipe 'powershell::powershell2'

case node['platform']
when 'windows'

require 'chef/win32/version'
windows_version = Chef::ReservedNames::Win32::Version.new

if windows_version.windows_server_2012_r2? || windows_version.windows_8_1?
# Handle WMFC install on 2012R2 and 8.1 only (yet)
if ::Windows::VersionHelper.nt_version(node) == 6.3
include_recipe 'powershell::powershell2'

include_recipe 'powershell::windows_reboot' unless node['powershell']['installation_reboot_mode'] == 'no_reboot'

windows_package 'Windows Management Framework Core 5.0' do
windows_package 'Windows Management Framework Core 5.0' do # ~FC009
source node['powershell']['powershell5']['url']
checksum node['powershell']['powershell5']['checksum']
installer_type :custom
Expand Down
16 changes: 7 additions & 9 deletions recipes/winrm.rb
Expand Up @@ -34,15 +34,13 @@
shell_out = Mixlib::ShellOut.new(winrm_cmd)
shell_out.run_command

if !shell_out.stdout.include? 'Transport = HTTPS'
# Create HTTPS listener
if node['powershell']['winrm']['enable_https_transport']
if node['powershell']['winrm']['thumbprint'].empty? || node['powershell']['winrm']['thumbprint'].nil?
Chef::Log.error('Please specify thumbprint in default attributes for enabling https transport.')
else
powershell_script 'winrm-create-https-listener' do
code "winrm create 'winrm/config/Listener?Address=*+Transport=HTTPS' '@{Hostname=\"#{node['powershell']['winrm']['hostname']}\"; CertificateThumbprint=\"#{node['powershell']['winrm']['thumbprint']}\"}'"
end
# Create HTTPS listener
if !shell_out.stdout.include?('Transport = HTTPS') && node['powershell']['winrm']['enable_https_transport']
if node['powershell']['winrm']['thumbprint'].nil? || node['powershell']['winrm']['thumbprint'].empty?
Chef::Log.error('Please specify thumbprint in default attributes for enabling https transport.')
else
powershell_script 'winrm-create-https-listener' do
code "winrm create 'winrm/config/Listener?Address=*+Transport=HTTPS' '@{Hostname=\"#{node['powershell']['winrm']['hostname']}\"; CertificateThumbprint=\"#{node['powershell']['winrm']['thumbprint']}\"}'"
end
end
else
Expand Down
113 changes: 38 additions & 75 deletions spec/libraries/powershell_module_provider_spec.rb
Expand Up @@ -17,14 +17,17 @@
#

require_relative '../../libraries/powershell_module_provider'
require 'tmpdir'

describe 'PowershellModuleProvider' do
before do
allow(Chef::Config).to receive(:[]).with(:file_cache_path).and_return 'C:/tmp'
allow(Chef::Config).to receive(:[]).with(:why_run).and_return false

@node = Chef::Node.new
@events = Chef::EventDispatch::Dispatcher.new
@run_context = Chef::RunContext.new(@node, {}, @events)
@new_resource = PowershellModule.new('testmodule', @run_context)
@new_resource.destination '/'
@provider = PowershellModuleProvider.new(@new_resource, @run_context)
end

Expand All @@ -37,7 +40,7 @@

describe 'action_uninstall:' do
it 'uninstall module' do
@provider.should_receive(:uninstall_module)
expect(@provider).to receive(:uninstall_module)
expect { @provider.run_action(:uninstall) }.to_not raise_error
end
end
Expand Down Expand Up @@ -67,78 +70,51 @@
end

describe 'download_extract_module:' do
context 'when download_url and target are nil' do
before do
ENV['PROGRAMW6432'] = 'C:\\PROGRAMW6432'
@ps_cmd = double
end
before do
allow(@provider).to receive(:module_exists?).and_return false
end

context 'when download_url and target are nil' do
it 'downloads the package' do
expect(Dir).to receive(:mktmpdir).and_return('C:/tmp/')
cmd_str = "powershell.exe Invoke-WebRequest testmodule -OutFile C:/tmp/testmodule.zip; $shell = new-object -com shell.application;$zip = $shell.NameSpace('C:\\tmp\\testmodule.zip'); $shell.Namespace('C:\\PROGRAMW6432\\WindowsPowerShell\\Modules').copyhere($zip.items(), 0x14);write-host $shell"
expect(Mixlib::ShellOut).to receive(:new).with(cmd_str).and_return(@ps_cmd)
expect(@ps_cmd).to receive(:run_command)
cmd_str = "powershell.exe Invoke-WebRequest testmodule -OutFile C:/tmp/testmodule.zip; $shell = new-object -com shell.application;$zip = $shell.NameSpace('C:\\tmp\\testmodule.zip'); $shell.Namespace('\\').copyhere($zip.items(), 0x14);write-host $shell"
expect(Mixlib::ShellOut).to receive(:new).with(cmd_str).and_return(double('ps_cmd', run_command: nil))

expect(@provider.send(:download_extract_module)).to eq('C:/tmp/testmodule.zip')
end
end

context 'when download_url is provided and target is nil' do
before do
ENV['PROGRAMW6432'] = 'C:\\PROGRAMW6432'
@ps_cmd = double
end

it 'downloads the package' do
expect(Dir).to receive(:mktmpdir).and_return('C:/tmp/')
cmd_str = "powershell.exe Invoke-WebRequest https://temp_download.com -OutFile C:/tmp/testmodule.zip; $shell = new-object -com shell.application;$zip = $shell.NameSpace('C:\\tmp\\testmodule.zip'); $shell.Namespace('C:\\PROGRAMW6432\\WindowsPowerShell\\Modules').copyhere($zip.items(), 0x14);write-host $shell"
expect(Mixlib::ShellOut).to receive(:new).with(cmd_str).and_return(@ps_cmd)
expect(@ps_cmd).to receive(:run_command)
cmd_str = "powershell.exe Invoke-WebRequest https:/temp_download.com -OutFile C:/tmp/testmodule.zip; $shell = new-object -com shell.application;$zip = $shell.NameSpace('C:\\tmp\\testmodule.zip'); $shell.Namespace('\\').copyhere($zip.items(), 0x14);write-host $shell"
expect(Mixlib::ShellOut).to receive(:new).with(cmd_str).and_return(double('ps_cmd', run_command: nil))

expect(@provider.send(:download_extract_module, 'https://temp_download.com')).to eq('C:/tmp/testmodule.zip')
expect(@provider.send(:download_extract_module, 'https:/temp_download.com')).to eq('C:/tmp/testmodule.zip')
end
end

context 'when download_url is nil and target is provided' do
before do
ENV['PROGRAMW6432'] = 'C:\\PROGRAMW6432'
@ps_cmd = double
end

it 'downloads the package' do
cmd_str = "powershell.exe Invoke-WebRequest testmodule -OutFile tmp/target1.zip; $shell = new-object -com shell.application;$zip = $shell.NameSpace('tmp\\target1.zip'); $shell.Namespace('C:\\PROGRAMW6432\\WindowsPowerShell\\Modules').copyhere($zip.items(), 0x14);write-host $shell"
expect(Mixlib::ShellOut).to receive(:new).with(cmd_str).and_return(@ps_cmd)
expect(@ps_cmd).to receive(:run_command)
cmd_str = "powershell.exe Invoke-WebRequest testmodule -OutFile tmp/target1.zip; $shell = new-object -com shell.application;$zip = $shell.NameSpace('tmp\\target1.zip'); $shell.Namespace('\\').copyhere($zip.items(), 0x14);write-host $shell"
expect(Mixlib::ShellOut).to receive(:new).with(cmd_str).and_return(double('ps_cmd', run_command: nil))

expect(@provider.send(:download_extract_module, nil, 'tmp/target1.zip')).to eq('tmp/target1.zip')
end
end

context 'when download_url and target are provided' do
before do
ENV['PROGRAMW6432'] = 'C:\\PROGRAMW6432'
@ps_cmd = double
end

it 'downloads the package' do
cmd_str = "powershell.exe Invoke-WebRequest https://temp_download.com -OutFile tmp/target1.zip; $shell = new-object -com shell.application;$zip = $shell.NameSpace('tmp\\target1.zip'); $shell.Namespace('C:\\PROGRAMW6432\\WindowsPowerShell\\Modules').copyhere($zip.items(), 0x14);write-host $shell"
expect(Mixlib::ShellOut).to receive(:new).with(cmd_str).and_return(@ps_cmd)
expect(@ps_cmd).to receive(:run_command)
cmd_str = "powershell.exe Invoke-WebRequest https:/temp_download.com -OutFile tmp/target1.zip; $shell = new-object -com shell.application;$zip = $shell.NameSpace('tmp\\target1.zip'); $shell.Namespace('\\').copyhere($zip.items(), 0x14);write-host $shell"
expect(Mixlib::ShellOut).to receive(:new).with(cmd_str).and_return(double('ps_cmd', run_command: nil))

expect(@provider.send(:download_extract_module, 'https://temp_download.com', 'tmp/target1.zip')).to eq('tmp/target1.zip')
expect(@provider.send(:download_extract_module, 'https:/temp_download.com', 'tmp/target1.zip')).to eq('tmp/target1.zip')
end
end
end

describe 'uninstall_module:' do
context 'when module directory exists' do
before do
ENV['PROGRAMW6432'] = 'C:/PROGRAMW6432'
@ps_cmd = double
end

it 'uninstalls module' do
module_dir = 'C:/PROGRAMW6432/WindowsPowerShell/Modules/testmodule'
module_dir = '/testmodule'
expect(Dir).to receive(:exist?).with(module_dir).and_return(true)
expect(FileUtils).to receive(:rm_rf).with(module_dir)
expect(Chef::Log).to receive(:info).with("Powershell Module 'testmodule' uninstallation completed successfully")
Expand All @@ -148,13 +124,8 @@
end

context 'when module directory does not exist' do
before do
ENV['PROGRAMW6432'] = 'C:/PROGRAMW6432'
@ps_cmd = double
end

it 'logs message' do
module_dir = 'C:/PROGRAMW6432/WindowsPowerShell/Modules/testmodule'
module_dir = '/testmodule'
expect(Dir).to receive(:exist?).with(module_dir).and_return(false)
expect(Chef::Log).to receive(:info).with("Unable to locate module 'testmodule'")

Expand All @@ -164,32 +135,18 @@
end

describe 'install_module:' do
before do
ENV['PROGRAMW6432'] = 'C:/PROGRAMW6432'
@ps_cmd = double
end

context 'install from local source' do
before do
@dir = Dir.tmpdir + '/testmodule'
FileUtils.mkdir_p(@dir) unless File.directory?(@dir)
@module_files = ["#{@dir}/test.psd1", "#{@dir}/test.psm1", "#{@dir}/test.dll"]
@module_files.each do |file|
File.new("#{file}", 'w+')
end
end

after do
FileUtils.rm_rf(@dir) if File.directory?(@dir)
end

it 'copies module from source to ps module path' do
@new_resource.source(@dir)
ps_module_path = 'C:/PROGRAMW6432/WindowsPowerShell/Modules/testmodule'
expect(Dir).to receive(:exist?).with('/tmp/testmodule').and_return(true)
ps_module_path = '/testmodule'
@new_resource.source(ps_module_path)

module_files = %W(#{ps_module_path}/*.psd1 #{ps_module_path}/*.psm1 #{ps_module_path}/*.dll)

expect(Dir).to receive(:exist?).with(ps_module_path).and_return(true)
expect(FileUtils).to receive(:mkdir_p).with(ps_module_path).and_return(["#{ps_module_path}"])
@module_files.each do |filename|
expect(Dir).to receive(:[]).with(*module_files).and_return module_files

module_files.each do |filename|
expect(FileUtils).to receive(:cp).with(filename, ps_module_path)
end

Expand All @@ -198,9 +155,15 @@
end
context 'source is a url' do
it 'downloads module from source and install' do
@new_resource.source('https://testmodule.com')
expect(@provider).to receive(:download_extract_module).and_return('C:/tmp/testmodule')
expect(FileUtils).to receive(:rm_rf).with('C:/tmp')
source = 'https:/testmodule.com'
destination = 'C:/tmp/testmodule'
@new_resource.source source

expect(Dir).to receive(:exist?).with(source).and_return(false)
expect(@provider).to receive(:download_extract_module).and_return(destination)
expect(File).to receive(:exist?).with(destination).and_return(true)
expect(FileUtils).to receive(:rm_f).with(destination)

@provider.send(:install_module)
end
end
Expand Down