Update the mediawiki cookbook and upstream cookbooks

Compatibility with Chef 14
This commit is contained in:
Greg Karékinian
2019-04-08 11:20:12 +02:00
parent 6e3e8cde1b
commit 777b85c2ab
312 changed files with 5603 additions and 14219 deletions

View File

@@ -1,2 +0,0 @@
~FC059
~FC016

View File

@@ -2,6 +2,298 @@
This file is used to list changes made in each version of the windows cookbook.
## 5.3.0 (2019-03-06)
- Expanded certificate testing to cover more scenarios - [@Xorima](https://github.com/Xorima)
- Updated windows_share to better compare the current and desired path in order to prevent converging on each Chef run - [@Xorima](https://github.com/Xorima)
- Backported all windows_certificate fixes from Chef 14.8 - 14.11 including improvements to importing the types of certificates that can be imported, suppport for nested certs, and support for importing private keys with certs.
## 5.2.4 (2019-02-28)
- Fix http_acl regex to properly capture SDDL - [@Annih](https://github.com/Annih)
- Updated windows_share to create share if the share is deleted, and to sanitize paths using Chef::Util::PathHelper.cleanpath (#607) - [@Xorima](https://github.com/Xorima)
## 5.3.3 (2019-01-30)
- Updated windows_certificate code to match that in Chef 14.10. This increases the requirement of the win32_certstore gem to the latest and resolves multiple issues with the previous implementation.
## 5.2.2 (2018-11-20)
- windows_share: Accounts to be revoked should be provided as an individually quoted string array
## 5.2.1 (2018-11-19)
- windows_share: Fix idempotency by not adding everyone by default
## 5.2.0 (2018-11-14)
- Support installing deleted features in windows_feature_dism
## 5.1.6 (2018-11-13)
- Add a warning to the readme regarding windows_share and windows_certificate now being included in Chef 14.7
- Deprecated win_friendly_path helper in favor of built-in helpers
## 5.1.5 (2018-11-07)
- Avoid deprecation warnings in windows_share and windows_certificate on Chef 14.7+ as these are now included in the chef-client itself.
## 5.1.4 (2018-10-30)
- Note the :verify action for windows_certificate in the readme
- certificate resource: auto set sensitive is passing password
## 5.1.3 (2018-10-11)
- Remove docs and test suite for windows tasks
- Changed variable name in log message for retrieving SMB share access
- Don't load the windows helper in windows_certificate
## 5.1.2 (2018-10-08)
- Fix typo in windows_feature_dism resource name
## 5.1.1 (2018-09-06)
- Require the win32-certstore gem and upgrade the gem as the resource runs so we get the most up to date version
- Remove redundant helper methods from the windows_certificate resource
## 5.1.0 (2018-08-29)
- Add an action to windows_user_privilege to remove a privilege
- Fix failing appveyor tests
- Require win32-certstore 0.1.8 which resolves several issues with the windows_certificate resource
- Avoid deprecation warnings with Chef 14.3+ by not loading resources that are now built into Chef
## 5.0.0 (2018-07-24)
### Breaking Changes
This release removes the windows_task and windows_path resources from this cookbook. This resources shipped in Chef 13.0 and 13.4 This raises the required version of chef-client for this cookbook to 13.4 or later.
## 4.3.4 (2018-07-18)
- Fix error message typo in windows_feature_powershell
- Use win32-certstore 0.1.7 for bugfixes
## 4.3.3 (2018-07-05)
- Fix failures on PS 3.0 in windows_feature_powershell
## 4.3.2 (2018-06-13)
- Don't error in windows_feature_dism when providing a source
## 4.3.1 (2018-06-11)
- Make sure to quote each individual user to grant share access to
## 4.3.0 (2018-06-11)
- Add the windows_user_privilege resource which can grant privileges like Logon As a Service
- Add windows_feature_powershell support for Windows 2008 R2 by not downcasing the feature names there and modifying the shell_out commands to make older output look like the 2012+ output
- windows_certificate resource has been reworked to use the new win32-certstore gem. This gem abstracts away much of the logic and will allow us to better support certificates on Windows, especially on non-english systems.
- Convert pester tests to InSpec for easier testing with ChefDK out of the box
- Added additional tests for better testing in AppVeyor
- Stop importing the servermanager module in windows_feature_powershell since we require PowerShell 3.0 and we don't need to do this there
- Improve the error messages in Windows feature to get the Windows versions right
- Increase readability in version logic with helpers in windows_feature resources
## 4.2.5 (2018-05-28)
- Add quoting to Path when creating new Share
## 4.2.4 (2018-05-14)
- Fix the platform version check in windows_share
## 4.2.3 (2018-05-07)
- Include the helper in the action class to prevent failures with the zipfile resource
## 4.2.2 (2018-04-24)
- Properly fail in windows_share on Windows 2008 R2 since we lack the cmdlets to manipulates shares on those systems.
## 4.2.1 (2018-04-17)
- Make sure shares can have spaces in the share name
## 4.2.0 (2018-04-16)
- Initial rewrite of windows_share to use PowerShell for share creation. This introduces multiple new properties and resolves a good number of longstanding issues. Please be sure to report any issues you see with this so we can stabilize this resource and include it in Chef 15!
- Resolve failures in windows_certificate
## 4.1.4 (2018-03-29)
- Raise in windows_feature_powershell if we're on PS < 3.0
## 4.1.3 (2018-03-28)
- Restore support for Windows 2008 R2 in windows_feature_dism
## 4.1.2 (2018-03-27)
- Improve creation messaging for shares
- Allow feature names to be case insensitive in windows_feature
## 4.1.1 (2018-03-23)
- Simplify delete action slightly in windows_pagefile
- Don't use win_friendly_path helper in windows_pagefile since we already coerce the path value
## 4.1.0 (2018-03-21)
- Adds Caching for WIndows Feature Powershell resource using the same sort of logic we use on windows_feature_dism. This gives us a 3.5X speedup when no features need to be changed (subsequent runs after the change)
- Warn if we're on w2k12 and trying to use source/management properties in windows_feature_powershell since that doesn't work.
- Properly parse features into arrays so installing an array of features works in dism/powershell. This is the preferred way to install a number of features and will be faster than a large number of feature resources
- Fix description of properties for pagefile in the readme
## 4.0.2 (2018-03-20)
- Enable FC016 testing
- Enable FC059 testing
- Properly calculate available packages if source is passed in windows_feature_dism resource
## 4.0.1 (2018-03-07)
Fix the previous update to windows_feature_dism to use 'override' level of attributes not the normal level which persists to the node. Thanks to @Annih for pointing out the mistake here.
## 4.0.0 (2018-03-05)
### WARNING
This release contains a complete rewrite to windows_feature_dism resource and includes several behavior changes to windows_feature resource. Make sure to read the complete list of changes below before deploying this to production systems.
#### DISM feature caching Ohai plugin replacement
In the 3.X cookbook we installed an Ohai plugin that cached the state of features on the node, and we reloaded that plugin anytime we installed/removed a feature from the system. This greatly sped up Chef runs where no features were actually installed/removed (2nd run and later). Without the caching each resource would take about 1 second longer while it queried current feature state. Using Ohai to cache this data was problematic though due to incompatibilities with Chef Solo, the reliance on the ohai cookbook, and the addition of extra node data which had to be stored on the Chef Server.
In the 4.0 release instead of caching data via an Ohai plugin we just write directly to the node within the resource. This avoids the need to load in the ohai plugin and the various issues that come with that. In the end it's basically the exact same thing, but less impacting on end users and faster when the data needs to be updated.
#### Fail when feature is missing in windows_feature_dism
The windows_feature_dism resource had a rather un-Chef behavior in which it just warned you if a feature wasn't available on your platform and then continued on silently. This isn't how we handle missing packages in any of our package resource and because of that it's not going to be what anyone expects out of the box. If someone really wants SNMP installed and we can't install it we should fail instead of continuing on as if we did install it. So we'll now do the following things:
- When installing a feature that doesn't exist: fail
- When removing a feature that doesn't exist: continue since it is technically removed
- When deleting a feature that doesn't exist: continue since it is technically deleted
For some users, particularly those writing community cookbooks, this is going to be a breaking change. I'd highly recommend putting logic within your cookbooks to only install features on supported releases of Windows. If you'd just like it to continue even with a failure you can also use `ignore_failure true` on your resource although this produces a lot of failure messaging in logs.
#### Properly support features as an array in windows_feature_dism
We claimed to support installing features as an array in the windows_feature_dism resource previously, but it didn't actually work. The actual result was a warning that the array of features wasn't available on your platform since we compared the array to available features as if it was a string. We now properly support installation as a array and we do validation on each feature in the array to make sure the features are available on your Windows release.
#### Install as the default action in windows_feature_powershell
Due to some previous refactoring the :install action was not the default action for windows_feature_powershell. For all other package resources in Chef install is the default so this would likely lead to some unexpected behavior in cookbooks. This is technically a breaking change, but I suspect everyone assumed :install was always the default.
#### servermanagercmd.exe Support Removal
This cookbook previously supported servermanagercmd.exe, which was necessary for feature installation on Windows 2003 / 2008 (not R2) systems. Windows 2003 went full EOL in 2015 and 2008 went into extended support in 2015\. Neither releases are supported platforms for Chef or this cookbook so we've chosen to simplify the code and remove support entirely.
#### Remove the undocumented node['windows']['rubyzipversion'] attribute
This attribute was a workaround for a bug in the rubyzip gem YEARS ago that's just not necessary anymore. We also never documented this attribute and a resource shouldn't change behavior based on attributes.
## 3.5.2 (2018-03-01)
- Remove value_for_feature_provider helper which wasn't being used and was using deprecated methods
- Add all the Windows Core editions to the version helper
- Simplify / speedup how we find the font directory in windows_font
- Don't bother enabling why-run mode in the resources since it's enabled by default
- Don't include mixlib-shellout in the resources since it's included by default
- Fix installation messaging for windows_feature_powershell to properly show all features being installed
- Use powershell for the share creation / deletion in windows_share. This speeds up the runs and fixes some of the failures.
## 3.5.1 (2018-02-23)
- Add a new `shortcut_name` property to `windows_shortcut`
- Use Chef's built in registry_key_exists helper in `windows_printer_port`
- Fix the `source` coerce in `windows_font`
## 3.5.0 (2018-02-23)
- Add Windows 2016 to the supported releases in the readme
- Add Windows 10 detection to the version helper
- Remove the Chefspec matchers. These are auto generated by ChefSpec now. If this causes your specs to fail upgrade ChefDK
- In `certificate_binding` support `hostnameport` option if address is a hostname
- Convert several tests to InSpec tests and add additional test scenarios
- Remove `required: true` on the name_properties, which serves no purpose and will be a Foodcritic rule in the next Foodcritic release
- Fix `windows_feature` logging to work when the user provides an array of features
- Don't both coercing a symbol into a symbol in the `windows_auto_run` resource.
- Switch `windows_font` over to the built in path helper in Chef, which a much more robust
- Don't coerce forward slashes to backslashes in the `windows_font` `source` property if the source is a URI
- Add a new `path` property to `windows_pagefile` for properly overriding the resource name
- Coerce backslashes to forward slashes in `windows_pagefile`'s `path` property so we do the right thing even if a user gives bad input
- Add a new `program_name` property in windows_auto_run for overriding the resource name
- Rename `program` property to `path` in windows_auto_run. The legacy name will continue to work, but cookbooks should be updated
- Coerce the `path` property to use backslashes in `windows_auto_run` so it works no matter what format of path the user provides
- Avoid writing out an extra space in `windows_auto_run`'s registry entry when the user doesn't specify an arg
- Added yard comments to many of the helper methods
## 3.4.4 (2018-01-19)
- Fix undefined method for 'ipv4_address' in windows_printer_port
## 3.4.3 (2018-01-04)
- Added missing parentheses around PersistKeySet flag that was preventing PowerShell from creating X509Certificate2 object
## 3.4.2 (2018-01-02)
- Add deprecation warnings for windows_path and windows_task which are now included in Chef 13\. These will be removed from this cookbook in Sept 2018.
## 3.4.1 (2017-12-06)
- Fix long-running filtering by replace LIKE with equality sign in the share resource
- Use logical OR instead of AND when trying to detect share permissions changing in the share resource
- Remove extra new_resource.updated_by_last_action in the windows_task resource that resulted in a Foodcritic warning
## 3.4.0 (2017-11-14)
- Add a root key property for the auto_run resource
- Fix a resource typo where a name_property was still written name_attribute
- Resolve FC108 warnings
## 3.3.0 (2017-11-06)
- Add new dns resource. See readme for examples
- Add BUILTIN\Users to SYSTEM_USERS for windows_task
## 3.2.0 (2017-10-17)
- Add management_tools property to windows_feature powershell provider which installs the various management tools
- Fix deprecations_namespace_collisions
- Add additional certificate store names
- Add the ability to define a timeout on windows_feature
- Multiple improvements to the font resource
- Improved logging, particularly debug logging
- Allow pulling the font from a remote location using remote_file
- Fix some failures in fetching local fonts
- Added a font_name property that allows you specify the local name of the font, which can be different from the name of the chef resource. This allows you to create more friendly resource names for your converge.
- Handle font resources with backslashes in their source
- Remove source property from servermanagercmd provider as it does not support it.
- Remove converge_by around inner powershell_script resource to stop it always reporting as changed
- Change install feature guards to work on Windows 2008r2
- Allow dism feature installs to work on non-English systems
## 3.1.3 (2017-09-18)
### windows_task and windows_path deprecation
s of chef-client 13.0+ and 13.4+ windows_task and windows_path are now included in the Chef client. windows_task underwent a full rewrite that greatly improved the functionality and idempotency of the resource. We highly recommend using these new resources by upgrading to Chef 13.4 or later. If you are running these more recent Chef releases the windows_task and windows_path resources within chef-client will take precedence over those in this cookbook. In September 2018 we will release a new major version of this cookbook that removes windows_task and windows_path.
## 3.1.2 (2017-08-14)
- Revert "Require path in the share resource instead of raising if it's missing" which was causing failures due to a bug in the chef-client
## 3.1.1 (2017-06-13)
- Replace Windows 7 testing with Windows 10 testing
@@ -34,7 +326,7 @@ This file is used to list changes made in each version of the windows cookbook.
## 3.0.1 (2017-03-17)
- Fix `windows_share` to be fully idempotent. Fixes #447
- Fix `windows_share` to be fully idempotent. Fixes #447
## 3.0.0 (2017-03-15)

View File

@@ -1,21 +0,0 @@
<!-- This is a generated file. Please do not edit directly -->
# Maintainers
This file lists how this cookbook project is maintained. When making changes to the system, this file tells you who needs to review your patch - you need a review from an existing maintainer for the cookbook to provide a :+1: on your pull request. Additionally, you need to not receive a veto from a Lieutenant or the Project Lead.
Check out [How Cookbooks are Maintained](https://github.com/chef-cookbooks/community_cookbook_documentation/blob/master/CONTRIBUTING.MD) for details on the process and how to become a maintainer or the project lead.
# Project Maintainer
* [Adam Edwards](https://github.com/adamedx)
# Maintainers
* [Adam Edwards](https://github.com/adamedx)
* [Kartik Null Cating-Subramanian](https://github.com/ksubrama)
* [Steven Murawski](https://github.com/smurawski)
* [Matt Wrock](https://github.com/mwrock)
* [Jay Mundrawala](https://github.com/jaym)
* [Claire McQuin](https://github.com/mcquin)
* [Salim Alam](https://github.com/chefsalim)
* [Tim Smith](https://github.com/tas50)
* [Jennifer Davis](https://github.com/sigje)

View File

@@ -12,15 +12,24 @@ Provides a set of Windows-specific resources to aid in the creation of cookbooks
- Windows Server 2008 R2
- Windows 8, 8.1
- Windows Server 2012 (R1, R2)
- Windows Server 2016
### Chef
- Chef 12.6+
- Chef 13.4+
## Resources
### Deprecated Resources Note
As of Chef Client 14.0+ the auto_run, feature, feature_dism, feature_powershell, font, pagefile, printer_port, printer, and shortcut resources are now included in the Chef Client. If you are running Chef 14+ the resources in Chef client will take precedence over the resources in this cookbook. In April 2019 we will release a new major version of this cookbook that removes these resources.
As of Chef 14.7+ the windows_share and windows_certificate resources are now included in the Chef Client. If you are running Chef 14.7+ the resources in Chef client will take precedence over the resources in this cookbook. In November 2019 we will release a new major version of this cookbook that removes these resources.
### windows_auto_run
`Note`: This resource is now included in Chef 14 and later. There is no need to depend on the Windows cookbook for this resource.
#### Actions
- `:create` - Create an item to be run at login
@@ -28,9 +37,10 @@ Provides a set of Windows-specific resources to aid in the creation of cookbooks
#### Properties
- `name` - Name attribute. The name of the value to be stored in the registry
- `program` - The program to be run at login
- `program_name` - Name property. The name of the value to be stored in the registry
- `path` - The program to be run at login. This property was previous named `program`. Cookbooks using the `program` property will continue to function, but should be updated.
- `args` - The arguments for the program
- `root` - The registry root key to put the entry under--`:machine` (default) or `:user`
#### Examples
@@ -46,6 +56,8 @@ end
### windows_certificate
`Note`: This resource is now included in Chef 14.7 and later. There is no need to depend on the Windows cookbook for this resource.
Installs a certificate into the Windows certificate store from a file, and grants read-only access to the private key for designated accounts. Due to current limitations in WinRM, installing certificated remotely may not work if the operation requires a user profile. Operations on the local machine store should still work.
#### Actions
@@ -53,13 +65,27 @@ Installs a certificate into the Windows certificate store from a file, and grant
- `:create` - creates or updates a certificate.
- `:delete` - deletes a certificate.
- `:acl_add` - adds read-only entries to a certificate's private key ACL.
- `:verify` - logs whether or not a certificate is valid
#### Properties
- `source` - name attribute. The source file (for create and acl_add), thumbprint (for delete and acl_add) or subject (for delete).
- `pfx_password` - the password to access the source if it is a pfx file.
- `private_key_acl` - array of 'domain\account' entries to be granted read-only access to the certificate's private key. This is not idempotent.
- `store_name` - the certificate store to manipulate. One of MY (default : personal store), CA (trusted intermediate store) or ROOT (trusted root store).
- `store_name` - the certificate store to manipulate. One of:
- MY (Personal)
- CA (Intermediate Certification Authorities)
- ROOT (Trusted Root Certification Authorities)
- TRUSTEDPUBLISHER (Trusted Publishers)
- CLIENTAUTHISSUER (Client Authentication Issuers)
- REMOTE DESKTOP (Remote Desktop)
- TRUSTEDDEVICES (Trusted Devices)
- WEBHOSTING (Web Hosting)
- AUTHROOT (Third-Party Root Certification Authorities)
- TRUSTEDPEOPLE (Trusted People)
- SMARTCARDROOT (Smart Card Trusted Roots)
- TRUST (Enterprise Trust)
- DISALLOWED (Untrusted Certificates)
- `user_store` - if false (default) then use the local machine store; if true then use the current user's store.
#### Examples
@@ -99,10 +125,25 @@ Binds a certificate to an HTTP port in order to enable TLS communication.
- `cert_name` - name attribute. The thumbprint(hash) or subject that identifies the certificate to be bound.
- `name_kind` - indicates the type of cert_name. One of :subject (default) or :hash.
- `address` - the address to bind against. Default is 0.0.0.0 (all IP addresses).
- `address` - the address to bind against. Default is 0.0.0.0 (all IP addresses). One of:
- IP v4 address `1.2.3.4`
- IP v6 address `[::1]`
- Host name `www.foo.com`
- `port` - the port to bind against. Default is 443.
- `app_id` - the GUID that defines the application that owns the binding. Default is the values used by IIS.
- `store_name` - the store to locate the certificate in. One of MY (default : personal store), CA (trusted intermediate store) or ROOT (trusted root store).
- `store_name` - the store to locate the certificate in. One of:
- MY (Personal)
- CA (Intermediate Certification Authorities)
- ROOT (Trusted Root Certification Authorities)
- TRUSTEDPUBLISHER (Trusted Publishers)
- CLIENTAUTHISSUER (Client Authentication Issuers)
- REMOTE DESKTOP (Remote Desktop)
- TRUSTEDDEVICES (Trusted Devices)
- WEBHOSTING (Web Hosting)
- AUTHROOT (Third-Party Root Certification Authorities)
- TRUSTEDPEOPLE (Trusted People)
- SMARTCARDROOT (Smart Card Trusted Roots)
- TRUST (Enterprise Trust)
#### Examples
@@ -122,8 +163,54 @@ windows_certificate_binding "me.acme.com" do
end
```
### windows_dns
Configures A and CNAME records in Windows DNS. This requires the DNSCMD to be installed, which is done by adding the DNS role to the server or installing the Remote Server Admin Tools.
#### Actions
- :create: creates/updates the DNS entry
- :delete: deletes the DNS entry
#### Properties
- host_name: name attribute. FQDN of the entry to act on.
- dns_server: the DNS server to update. Default is local machine (.)
- record_type: the type of record to create. One of A (default) or CNAME
- target: for A records an array of IP addresses to associate with the host; for CNAME records the FQDN of the host to alias
- ttl: if > 0 then set the time to live of the record
#### Examples
```ruby
# Create A record linked to 2 addresses with a 10 minute ttl
windows_dns "m1.chef.test" do
target ['10.9.8.7', '1.2.3.4']
ttl 600
end
```
```ruby
# Delete records. target is mandatory although not used
windows_dns "m1.chef.test" do
action :delete
target []
end
```
```ruby
# Set an alias against the node in a role
nodes = search( :node, "role:my_service" )
windows_dns "myservice.chef.test" do
record_type 'CNAME'
target nodes[0]['fqdn']
end
```
### windows_feature
`Note`: This resource is now included in Chef 14 and later. There is no need to depend on the Windows cookbook for this resource.
**BREAKING CHANGE - Version 3.0.0**
This resource has been moved from using LWRPs and multiple providers to using Custom Resources. To maintain functionality, you'll need to change `provider` to `install_method`.
@@ -132,7 +219,7 @@ Windows Roles and Features can be thought of as built-in operating system packag
This resource allows you to manage these 'features' in an unattended, idempotent way.
There are three methods for the `windows_feature` which map into Microsoft's three major tools for managing roles/features: [Deployment Image Servicing and Management (DISM)](http://msdn.microsoft.com/en-us/library/dd371719%28v=vs.85%29.aspx), [Servermanagercmd](http://technet.microsoft.com/en-us/library/ee344834%28WS.10%29.aspx) (The CLI for Server Manager), and [PowerShell](https://technet.microsoft.com/en-us/library/cc731774(v=ws.11).aspx). As Servermanagercmd is deprecated, Chef will set the default method to `:windows_feature_dism` if `dism.exe` is present on the system being configured. The default method will fall back to `:windows_feature_servermanagercmd`, and then `:windows_feature_powershell`.
There are two underlying resources that power `windows_feature` which map to the available installation systems on supported releases of Windows: [Deployment Image Servicing and Management (DISM)](http://msdn.microsoft.com/en-us/library/dd371719%28v=vs.85%29.aspx) and [PowerShell](https://technet.microsoft.com/en-us/library/cc731774(v=ws.11).aspx). Chef will set the default method to `:windows_feature_dism` if `dism.exe` is present on the system being configured and otherwise use `:windows_feature_powershell`.
For more information on Roles, Role Services and Features see the [Microsoft TechNet article on the topic](http://technet.microsoft.com/en-us/library/cc754923.aspx). For a complete list of all features that are available on a node type either of the following commands at a command prompt:
@@ -142,12 +229,6 @@ For Dism:
dism /online /Get-Features
```
For ServerManagerCmd:
```text
servermanagercmd -query
```
For PowerShell:
```text
@@ -158,14 +239,16 @@ get-windowsfeature
- `:install` - install a Windows role/feature
- `:remove` - remove a Windows role/feature
- `:delete` - remove a Windows role/feature from the image (not supported by ServerManagerCmd)
- `:delete` - remove a Windows role/feature from the image
#### Properties
- `feature_name` - name of the feature/role(s) to install. The same feature may have different names depending on the provider used (ie DHCPServer vs DHCP; DNS-Server-Full-Role vs DNS).
- `all` - Boolean. Optional. Default: false. DISM and Powershell providers only. Forces all dependencies to be installed.
- `source` - String. Optional. DISM provider only. Uses local repository for feature install.
- `install_method` - Symbol. Optional. **REPLACEMENT FOR THE PREVIOUS PROVIDER OPTION** If not supplied, Chef will determine which method to use (in the order of `:windows_feature_dism`, `:windows_feature_servercmd`, `:windows_feature_powershell`)
- `feature_name` - name of the feature/role(s) to install. The same feature may have different names depending on the underlying resource being used (ie DHCPServer vs DHCP; DNS-Server-Full-Role vs DNS).
- `all` - Boolean. Optional. Default: false. For DISM this is the equivalent of specifying the /All switch to dism.exe, forcing all parent dependencies to be installed. With the PowerShell install method, the `-InstallAllSubFeatures` switch is applied. Note that these two methods may not produce identical results.
- `management_tools` - Boolean. Optional. Default: false. PowerShell only. Includes the `-IncludeManagementTools` switch. Installs all applicable management tools of the roles, role services, or features specified by the feature name.
- `source` - String. Optional. Uses local repository for feature install.
- `timeout` - Integer. Optional. Default: 600\. Specifies a timeout (in seconds) for feature install.
- `install_method` - Symbol. Optional. If not supplied, Chef will determine which method to use (in the order of `:windows_feature_dism`, `:windows_feature_servercmd`, `:windows_feature_powershell`)
#### Examples
@@ -177,13 +260,14 @@ windows_feature 'DHCPServer' do
end
```
Install the .Net 3.5.1 feature on Server 2012 using repository files on DVD and install all dependencies
Install the .Net 3.5.1 feature on Server 2012 using repository files on DVD and install all dependencies with a timeout of 900 seconds
```ruby
windows_feature "NetFx3" do
action :install
all true
source "d:\sources\sxs"
timeout 900
end
```
@@ -214,11 +298,21 @@ windows_feature ['Web-Asp-Net45', 'Web-Net-Ext45'] do
end
```
Install the Network Policy and Access Service feature, including the management tools. Which, for this example, will automatically install `RSAT-NPAS` as well.
```ruby
windows_feature 'NPAS' do
action :install
management_tools true
install_method :windows_feature_powershell
end
```
### windows_font
Installs a font.
`Note`: This resource is now included in Chef 14 and later. There is no need to depend on the Windows cookbook for this resource.
Font files should be included in the cookbooks
Installs font files. Sources the font by default from the cookbook, but a URI source can be specified as well.
#### Actions
@@ -226,13 +320,17 @@ Font files should be included in the cookbooks
#### Properties
- `name` - The file name of the font file name to install. The path defaults to the files/default directory of the cookbook you're calling windows_font from. Defaults to the resource name.
- `source` - Set an alternate path to the font file.
- `font_name` - The file name of the font file name to install. The path defaults to the files/default directory of the cookbook you're calling windows_font from. Defaults to the resource name.
- `source` - A local filesystem path or URI to source the font file from..
#### Examples
```ruby
windows_font 'Code New Roman.otf'
windows_font 'Custom.otf' do
source "https://example.com/Custom.otf"
end
```
### windows_http_acl
@@ -248,7 +346,7 @@ Sets the Access Control List for an http URL to grant non-admin accounts permiss
- `url` - the name of the url to be created/deleted.
- `sddl` - the DACL string configuring all permissions to URL. Mandatory for create if user is not provided. Can't be use with `user`.
- `user` - the name (domain\user) of the user or group to be granted permission to the URL. Mandatory for create if sddl is not provided. Can't be use with `sddl`. Only one user or group can be granted permission so this replaces any previously defined entry.
- `user` - the name (domain\user) of the user or group to be granted permission to the URL. Mandatory for create if sddl is not provided. Can't be use with `sddl`. Only one user or group can be granted permission so this replaces any previously defined entry. If you receive a parameter error your user may not exist.
#### Examples
@@ -273,8 +371,9 @@ end
### windows_pagefile
Configures the file that provides virtual memory for applications requiring more memory than available RAM or that are paged out to free up memory in use.
`Note`: This resource is now included in Chef 14 and later. There is no need to depend on the Windows cookbook for this resource.
Configures the file that provides virtual memory for applications requiring more memory than available RAM or that are paged out to free up memory in use.
#### Actions
@@ -283,14 +382,16 @@ Configures the file that provides virtual memory for applications requiring more
#### Properties
- `name` - the path to the pagefile, String, name_property: true
- `path` - the path to the pagefile, String, name_property: true
- `system_managed` - configures whether the system manages the pagefile size. [true, false]
- `automatic_managed` - all of the settings are managed by the system. If this is set to true, other settings will be ignored. [true, false], default: false
- `initial_size` - initial size of the pagefile in bytes. Integer
- `maximum_size` - maximum size of the pagefile in bytes. Integer
- `initial_size` - initial size of the pagefile in megbytes. Integer
- `maximum_size` - maximum size of the pagefile in megbytes. Integer
### windows_printer_port
`Note`: This resource is now included in Chef 14 and later. There is no need to depend on the Windows cookbook for this resource.
Create and delete TCP/IPv4 printer ports.
#### Actions
@@ -346,25 +447,27 @@ end
### windows_printer
`Note`: This resource is now included in Chef 14 and later. There is no need to depend on the Windows cookbook for this resource.
Create Windows printer. Note that this doesn't currently install a printer driver. You must already have the driver installed on the system.
The Windows Printer LWRP will automatically create a TCP/IP printer port for you using the `ipv4_address` property. If you want more granular control over the printer port, just create it using the `windows_printer_port` LWRP before creating the printer.
The Windows Printer resource will automatically create a TCP/IP printer port for you using the `ipv4_address` property. If you want more granular control over the printer port, just create it using the `windows_printer_port` resource before creating the printer.
#### Actions
- `:create` - Create a new printer
- `:delete` - Delete a new printer
- `:delete` - Delete an existing printer
#### Properties
- `device_id` - Name attribute. Required. Printer queue name, e.g. 'HP LJ 5200 in fifth floor copy room'
- `device_id` - Printer queue name, e.g. 'HP LJ 5200 in fifth floor copy room'. Name property.
- `comment` - Optional string describing the printer queue.
- `default` - Boolean. Optional. Defaults to false. Note that Windows sets the first printer defined to the default printer regardless of this setting.
- `driver_name` - String. Required. Exact name of printer driver. Note that the printer driver must already be installed on the node.
- `location` - Printer location, e.g. 'Fifth floor copy room', or 'US/NYC/Floor42/Room4207'
- `shared` - Boolean. Defaults to false.
- `share_name` - Printer share name.
- `ipv4_address` - Printer IPv4 address, e.g. '10.4.64.23'. You don't have to be able to ping the IP address to set it. Required.
- `ipv4_address` - Printer's IPv4 address, e.g. '10.4.64.23'. You don't have to be able to ping the IP address to set it. Required.
An error of "Set-WmiInstance : Generic failure" is most likely due to the printer driver name not matching or not being installed.
@@ -389,21 +492,33 @@ end
### windows_share
`Note`: This resource is now included in Chef 14.7 and later. There is no need to depend on the Windows cookbook for this resource.
Creates, modifies and removes Windows shares. All properties are idempotent.
`Note`: This resource uses PowerShell cmdlets introduced in Windows 2012/8.
#### Actions
- :create: creates/modifies a share
- :delete: deletes a share
- `:create`: creates/modifies a share
- `:delete`: deletes a share
#### Properties
- share_name: name attribute, the share name.
- path: path to the directory to be shared. Required when creating. If the share already exists on a different path then it is deleted and re-created.
- description: description to be applied to the share
- full_users: array of users which should have "Full control" permissions
- change_users: array of users which should have "Change" permissions
- read_users: array of users which should have "Read" permissions
property | type | default | description
------------------------ | ---------- | ------------- | -----------------------------------------------------------------------------------------------------------------------------------------------------------
`share_name` | String | resource name | the share to assign to the share
`path` | String | | The path of the location of the folder to share. Required when creating. If the share already exists on a different path then it is deleted and re-created.
`description` | String | | description to be applied to the share
`full_users` | Array | [] | users which should have "Full control" permissions
`change_users` | Array | [] | Users are granted modify permission to access the share.
`read_users` | Array | [] | users which should have "Read" permissions
`temporary` | True/False | false | The lifetime of the new SMB share. A temporary share does not persist beyond the next restart of the computer
`scope_name` | String | '*' | The scope name of the share.
`ca_timeout` | Integer | 0 | The continuous availability time-out for the share.
`continuously_available` | True/False | false | Indicates that the share is continuously available.
`concurrent_user_limit` | Integer | 0 (unlimited) | The maximum number of concurrently connected users the share can accommodate
`encrypt_data` | True/False | false | Indicates that the share is encrypted.
#### Examples
@@ -424,6 +539,8 @@ end
### windows_shortcut
`Note`: This resource is now included in Chef 14 and later. There is no need to depend on the Windows cookbook for this resource.
Creates and modifies Windows shortcuts.
#### Actions
@@ -432,8 +549,8 @@ Creates and modifies Windows shortcuts.
#### Properties
- `name` - name attribute. The shortcut to create/modify.
- `target` - what the shortcut links to
- `shortcut_name` - The name for the shortcut if it differs from the resource name. Name property
- `target` - Where the shortcut links to.
- `arguments` - arguments to pass to the target when the shortcut is executed
- `description` - description of the shortcut
- `cwd` - Working directory to use when the target is executed
@@ -441,27 +558,19 @@ Creates and modifies Windows shortcuts.
#### Examples
Add a shortcut all users desktop:
Add a shortcut to all users desktop:
```ruby
require 'win32ole'
all_users_desktop = WIN32OLE.new("WScript.Shell").SpecialFolders("AllUsersDesktop")
windows_shortcut "#{all_users_desktop}/Notepad.lnk" do
target "C:\\WINDOWS\\notepad.exe"
target "C:\\Windows\\notepad.exe"
description "Launch Notepad"
iconlocation "C:\\windows\\notepad.exe, 0"
iconlocation "C:\\Windows\\notepad.exe,0"
end
```
#### Library Methods
```ruby
Registry.value_exists?('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run','BGINFO')
Registry.key_exists?('HKLM\SOFTWARE\Microsoft')
BgInfo = Registry.get_value('HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run','BGINFO')
```
### windows_path
#### Actions
@@ -491,88 +600,87 @@ windows_path 'C:\7-Zip' do
end
```
### windows_task
### windows_user_privilege
Creates, deletes or runs a Windows scheduled task. Requires Windows Server 2008 due to API usage.
Adds the `principal` (User/Group) to the specified privileges (such as `Logon as a batch job` or `Logon as a Service`).
#### Actions
- `:create` - creates a task (or updates existing if user or command has changed)
- `:delete` - deletes a task
- `:run` - runs a task
- `:end` - ends a task
- `:change` - changes the un/pw or command of a task
- `:enable` - enable a task
- `:disable` - disable a task
- `:add` - add the specified privileges to the `principal`
- `:remove` - remove the specified privilege of the `principal`
#### Properties
- `task_name` - name attribute, The task name. ("Task Name" or "/Task Name")
- `force` - When used with create, will update the task.
- `command` - The command the task will run.
- `cwd` - The directory the task will be run from.
- `user` - The user to run the task as. (defaults to 'SYSTEM')
- `password` - The user's password. (requires user)
- `run_level` - Run with `:limited` or `:highest` privileges.
- `frequency` - Frequency with which to run the task. (default is :hourly. Other valid values include :minute, :hourly, :daily, :weekly, :monthly, :once, :on_logon, :onstart, :on_idle) :once requires start_time
- `frequency_modifier` - Multiple for frequency. (15 minutes, 2 days). Monthly tasks may also use these values": ('FIRST', 'SECOND', 'THIRD', 'FOURTH', 'LAST', 'LASTDAY')
- `start_day` - Specifies the first date on which the task runs. Optional string (MM/DD/YYYY)
- `start_time` - Specifies the start time to run the task. Optional string (HH:mm)
- `interactive_enabled` - (Allow task to run interactively or non-interactively. Requires user and password.)
- `day` - For monthly or weekly tasks, the day(s) on which the task runs. (MON - SUN, *, 1 - 31)
- `months` - The Months of the year on which the task runs. (JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC, *). Multiple months should be comma delimited.
- `idle_time` - For :on_idle frequency, the time (in minutes) without user activity that must pass to trigger the task. (1 - 999)
- `principal` - Name attribute, Required, String. The user or group to be granted privileges.
- `privilege` - Required, String/Array. The privilege(s) to be granted.
#### Examples
Create a `chef-client` task with TaskPath `\` running every 15 minutes
Grant the Administrator user the `Logon as a batch job` and `Logon as a service` privilege.
```ruby
windows_task 'chef-client' do
user 'Administrator'
password '$ecR3t'
cwd 'C:\\chef\\bin'
command 'chef-client -L C:\\tmp\\'
run_level :highest
frequency :minute
frequency_modifier 15
windows_user_privilege 'Administrator' do
privilege %w(SeBatchLogonRight SeServiceLogonRight)
end
```
Update `chef-client` task with new password and log location
Remove `Logon as a batch job` privilege of Administrator.
```ruby
windows_task 'chef-client' do
user 'Administrator'
password 'N3wPassW0Rd'
cwd 'C:\\chef\\bin'
command 'chef-client -L C:\\chef\\logs\\'
action :change
windows_user_privilege 'Administrator' do
privilege %w(SeBatchLogonRight)
action :remove
end
```
Delete a task named `old task`
#### Available Privileges
```ruby
windows_task 'old task' do
action :delete
end
```
Enable a task named `chef-client`
```ruby
windows_task 'chef-client' do
action :enable
end
```
Disable a task named `ProgramDataUpdater` with TaskPath `\Microsoft\Windows\Application Experience\`
```ruby
windows_task '\Microsoft\Windows\Application Experience\ProgramDataUpdater' do
action :disable
end
SeTrustedCredManAccessPrivilege Access Credential Manager as a trusted caller
SeNetworkLogonRight Access this computer from the network
SeTcbPrivilege Act as part of the operating system
SeMachineAccountPrivilege Add workstations to domain
SeIncreaseQuotaPrivilege Adjust memory quotas for a process
SeInteractiveLogonRight Allow log on locally
SeRemoteInteractiveLogonRight Allow log on through Remote Desktop Services
SeBackupPrivilege Back up files and directories
SeChangeNotifyPrivilege Bypass traverse checking
SeSystemtimePrivilege Change the system time
SeTimeZonePrivilege Change the time zone
SeCreatePagefilePrivilege Create a pagefile
SeCreateTokenPrivilege Create a token object
SeCreateGlobalPrivilege Create global objects
SeCreatePermanentPrivilege Create permanent shared objects
SeCreateSymbolicLinkPrivilege Create symbolic links
SeDebugPrivilege Debug programs
SeDenyNetworkLogonRight Deny access this computer from the network
SeDenyBatchLogonRight Deny log on as a batch job
SeDenyServiceLogonRight Deny log on as a service
SeDenyInteractiveLogonRight Deny log on locally
SeDenyRemoteInteractiveLogonRight Deny log on through Remote Desktop Services
SeEnableDelegationPrivilege Enable computer and user accounts to be trusted for delegation
SeRemoteShutdownPrivilege Force shutdown from a remote system
SeAuditPrivilege Generate security audits
SeImpersonatePrivilege Impersonate a client after authentication
SeIncreaseWorkingSetPrivilege Increase a process working set
SeIncreaseBasePriorityPrivilege Increase scheduling priority
SeLoadDriverPrivilege Load and unload device drivers
SeLockMemoryPrivilege Lock pages in memory
SeBatchLogonRight Log on as a batch job
SeServiceLogonRight Log on as a service
SeSecurityPrivilege Manage auditing and security log
SeRelabelPrivilege Modify an object label
SeSystemEnvironmentPrivilege Modify firmware environment values
SeManageVolumePrivilege Perform volume maintenance tasks
SeProfileSingleProcessPrivilege Profile single process
SeSystemProfilePrivilege Profile system performance
SeUnsolicitedInputPrivilege "Read unsolicited input from a terminal device"
SeUndockPrivilege Remove computer from docking station
SeAssignPrimaryTokenPrivilege Replace a process level token
SeRestorePrivilege Restore files and directories
SeShutdownPrivilege Shut down the system
SeSyncAgentPrivilege Synchronize directory service data
SeTakeOwnershipPrivilege Take ownership of files or other objects
```
### windows_zipfile
@@ -714,60 +822,6 @@ case ::Windows::VersionHelper.nt_version node
end
```
## Windows ChefSpec Matchers
The Windows cookbook includes custom [ChefSpec](https://github.com/sethvargo/chefspec) matchers you can use to test your own cookbooks that consume Windows cookbook LWRPs.
### Example Matcher Usage
```ruby
expect(chef_run).to install_windows_package('Node.js').with(
source: 'http://nodejs.org/dist/v0.10.26/x64/node-v0.10.26-x64.msi')
```
### Windows Cookbook Matchers
- create_windows_auto_run
- remove_windows_auto_run
- create_windows_certificate
- delete_windows_certificate
- add_acl_to_windows_certificate
- create_windows_certificate_binding
- delete_windows_certificate_binding
- install_windows_feature
- install_windows_feature_dism
- install_windows_feature_servermanagercmd
- install_windows_feature_powershell
- remove_windows_feature
- remove_windows_feature_dism
- remove_windows_feature_servermanagercmd
- remove_windows_feature_powershell
- delete_windows_feature
- delete_windows_feature_dism
- delete_windows_feature_powershell
- install_windows_font
- create_windows_http_acl
- delete_windows_http_acl
- install_windows_package
- remove_windows_package
- set_windows_pagefile
- add_windows_path
- remove_windows_path
- create_windows_printer
- delete_windows_printer
- create_windows_printer_port
- delete_windows_printer_port
- create_windows_shortcut
- create_windows_shortcut
- create_windows_task
- disable_windows_task
- enable_windows_task
- delete_windows_task
- run_windows_task
- change_windows_task
- unzip_windows_zipfile_to
- zip_windows_zipfile_to
## Usage
Place an explicit dependency on this cookbook (using depends in the cookbook's metadata.rb) from any cookbook where you would like to use the Windows-specific resources/providers that ship with this cookbook.
@@ -784,7 +838,7 @@ depends 'windows'
- Author:: Doug Ireton ([doug.ireton@nordstrom.com](mailto:doug.ireton@nordstrom.com))
```text
Copyright 2011-2016, Chef Software, Inc.
Copyright 2011-2018, Chef Software, Inc.
Copyright 2010, VMware, Inc.
Copyright 2011, Business Intelligence Associates, Inc
Copyright 2012, Nordstrom, Inc.

View File

@@ -1,45 +0,0 @@
#
# Author:: Wade Peacock <wade.peacock@visioncritical.com>
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
# limitations under the License.
#
Ohai.plugin(:DismFeatures) do
provides 'dism_features'
collect_data(:windows) do
dism_features Mash.new
# This is for 32-bit ruby/chef client on 64-bit Windows
# This emulates the locate_sysnative_cmd helper as it is not available
cmd = 'dism.exe'
dism = if ::File.exist?("#{ENV['WINDIR']}\\sysnative\\#{cmd}")
"#{ENV['WINDIR']}\\sysnative\\#{cmd}"
elsif ::File.exist?("#{ENV['WINDIR']}\\system32\\#{cmd}")
"#{ENV['WINDIR']}\\system32\\#{cmd}"
else
cmd
end
# Grab raw feature information from dism command line
raw_list_of_features = shell_out("#{dism} /Get-Features /Online /Format:Table").stdout
# Split stdout into an array by windows line ending
features_list = raw_list_of_features.split("\r\n")
features_list.each do |feature_details_raw|
# Skip lines that do not match Enable / Disable
next unless feature_details_raw =~ /(En|Dis)able/
# Strip trailing whitespace characters then split on n number of spaces + | + n number of spaces
feature_details = feature_details_raw.strip.split(/\s+[|]\s+/)
# Add to Mash
dism_features[feature_details.first] = feature_details.last
end
end
end

View File

@@ -1,586 +0,0 @@
if defined?(ChefSpec)
ChefSpec.define_matcher :windows_auto_run
ChefSpec.define_matcher :windows_certificate
ChefSpec.define_matcher :windows_certificate_binding
ChefSpec.define_matcher :windows_feature
ChefSpec.define_matcher :windows_feature_dism
ChefSpec.define_matcher :windows_feature_servermanagercmd
ChefSpec.define_matcher :windows_feature_powershell
ChefSpec.define_matcher :windows_font
ChefSpec.define_matcher :windows_http_acl
ChefSpec.define_matcher :windows_pagefile
ChefSpec.define_matcher :windows_path
ChefSpec.define_matcher :windows_printer
ChefSpec.define_matcher :windows_printer_port
ChefSpec.define_matcher :windows_share
ChefSpec.define_matcher :windows_shortcut
ChefSpec.define_matcher :windows_task
ChefSpec.define_matcher :windows_zipfile
#
# Assert that a +windows_certificate+ resource exists in the Chef run with the
# action +:create+. Given a Chef Recipe that creates 'c:\test\mycert.pfx' as a
# +windows_certificate+:
#
# windows_certificate 'c:\test\mycert.pfx' do
# action :create
# end
#
# The Examples section demonstrates the different ways to test a
# +windows_certificate+ resource with ChefSpec.
#
# @example Assert that a +windows_certificate+ was created
# expect(chef_run).to create_windows_certificate('c:\test\mycert.pfx')
#
#
# @param [String, Regex] resource_name
# the name of the resource to match
#
# @return [ChefSpec::Matchers::ResourceMatcher]
#
def create_windows_certificate(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_certificate, :create, resource_name)
end
#
# Assert that a +windows_certificate+ resource exists in the Chef run with the
# action +:delete+. Given a Chef Recipe that deletes "me.acme.com" as a
# +windows_certificate+:
#
# windows_certificate 'me.acme.com' do
# action :delete
# end
#
# The Examples section demonstrates the different ways to test a
# +windows_certificate+ resource with ChefSpec.
#
# @example Assert that a +windows_certificate+ was _not_ deleted
# expect(chef_run).to_not delete_windows_certificate('me.acme.com')
#
#
# @param [String, Regex] resource_name
# the name of the resource to match
#
# @return [ChefSpec::Matchers::ResourceMatcher]
#
def delete_windows_certificate(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_certificate, :delete, resource_name)
end
#
# Assert that a +windows_certificate+ resource exists in the Chef run with the
# action +:acl_add+. Given a Chef Recipe that adds a private key acl to "me.acme.com" as a
# +windows_certificate+:
#
# windows_certificate 'me.acme.com' do
# private_key_acl ['acme\fred', 'pc\jane']
# action :acl_add
# end
#
# The Examples section demonstrates the different ways to test a
# +windows_certificate+ resource with ChefSpec.
#
# @example Assert that a +windows_certificate+ was _not_ removed
# expect(chef_run).to add_acl_to_windows_certificate('me.acme.com').with(private_key_acl: ['acme\fred', 'pc\jane'])
#
#
# @param [String, Regex] resource_name
# the name of the resource to match
#
# @return [ChefSpec::Matchers::ResourceMatcher]
#
def add_acl_to_windows_certificate(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_certificate, :acl_add, resource_name)
end
#
# Assert that a +windows_feature+ resource exists in the Chef run with the
# action +:install+. Given a Chef Recipe that installs "NetFX3" as a
# +windows_feature+:
#
# windows_feature 'NetFX3' do
# action :install
# end
#
# The Examples section demonstrates the different ways to test a
# +windows_feature+ resource with ChefSpec.
#
# @example Assert that a +windows_feature+ was installed
# expect(chef_run).to install_windows_feature('NetFX3')
#
# @example Assert that a +windows_feature+ was _not_ installed
# expect(chef_run).to_not install_windows_feature('NetFX3')
#
#
# @param [String, Regex] resource_name
# the name of the resource to match
#
# @return [ChefSpec::Matchers::ResourceMatcher]
#
def install_windows_feature(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_feature, :install, resource_name)
end
def install_windows_feature_servermanagercmd(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_feature_servermanagercmd, :install, resource_name)
end
def install_windows_feature_dism(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_feature_dism, :install, resource_name)
end
def install_windows_feature_powershell(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_feature_powershell, :install, resource_name)
end
#
# Assert that a +windows_feature+ resource exists in the Chef run with the
# action +:remove+. Given a Chef Recipe that removes "NetFX3" as a
# +windows_feature+:
#
# windows_feature 'NetFX3' do
# action :remove
# end
#
# The Examples section demonstrates the different ways to test a
# +windows_feature+ resource with ChefSpec.
#
# @example Assert that a +windows_feature+ was removed
# expect(chef_run).to remove_windows_feature('NetFX3')
#
#
# @param [String, Regex] resource_name
# the name of the resource to match
#
# @return [ChefSpec::Matchers::ResourceMatcher]
#
def remove_windows_feature(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_feature, :remove, resource_name)
end
def remove_windows_feature_servermanagercmd(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_feature_servermanagercmd, :remove, resource_name)
end
def remove_windows_feature_dism(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_feature_dism, :remove, resource_name)
end
def remove_windows_feature_powershell(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_feature_powershell, :remove, resource_name)
end
#
# Assert that a +windows_feature+ resource exists in the Chef run with the
# action +:delete+. Given a Chef Recipe that deletes "NetFX3" as a
# +windows_feature+:
#
# windows_feature 'NetFX3' do
# action :delete
# end
#
# The Examples section demonstrates the different ways to test a
# +windows_feature+ resource with ChefSpec.
#
# @example Assert that a +windows_feature+ was deleted
# expect(chef_run).to delete_windows_feature('NetFX3')
#
#
# @param [String, Regex] resource_name
# the name of the resource to match
#
# @return [ChefSpec::Matchers::ResourceMatcher]
#
def delete_windows_feature(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_feature, :delete, resource_name)
end
def delete_windows_feature_dism(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_feature_dism, :delete, resource_name)
end
def delete_windows_feature_powershell(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_feature_powershell, :delete, resource_name)
end
#
# Assert that a +windows_task+ resource exists in the Chef run with the
# action +:create+. Given a Chef Recipe that creates "mytask" as a
# +windows_task+:
#
# windows_task 'mytask' do
# command 'mybatch.bat'
# action :create
# end
#
# The Examples section demonstrates the different ways to test a
# +windows_task+ resource with ChefSpec.
#
# @example Assert that a +windows_task+ was created
# expect(chef_run).to create_windows_task('mytask')
#
#
# @param [String, Regex] resource_name
# the name of the resource to match
#
# @return [ChefSpec::Matchers::ResourceMatcher]
#
def create_windows_task(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_task, :create, resource_name)
end
#
# Assert that a +windows_task+ resource exists in the Chef run with the
# action +:disable+. Given a Chef Recipe that creates "mytask" as a
# +windows_task+:
#
# windows_task 'mytask' do
# action :disable
# end
#
# The Examples section demonstrates the different ways to test a
# +windows_task+ resource with ChefSpec.
#
# @example Assert that a +windows_task+ was disabled
# expect(chef_run).to disable_windows_task('mytask')
#
#
# @param [String, Regex] resource_name
# the name of the resource to match
#
# @return [ChefSpec::Matchers::ResourceMatcher]
#
def disable_windows_task(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_task, :disable, resource_name)
end
#
# Assert that a +windows_task+ resource exists in the Chef run with the
# action +:enable+. Given a Chef Recipe that creates "mytask" as a
# +windows_task+:
#
# windows_task 'mytask' do
# action :enable
# end
#
# The Examples section demonstrates the different ways to test a
# +windows_task+ resource with ChefSpec.
#
# @example Assert that a +windows_task+ was enabled
# expect(chef_run).to enable_windows_task('mytask')
#
#
# @param [String, Regex] resource_name
# the name of the resource to match
#
# @return [ChefSpec::Matchers::ResourceMatcher]
#
def enable_windows_task(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_task, :enable, resource_name)
end
#
# Assert that a +windows_task+ resource exists in the Chef run with the
# action +:delete+. Given a Chef Recipe that deletes "mytask" as a
# +windows_task+:
#
# windows_task 'mytask' do
# action :delete
# end
#
# The Examples section demonstrates the different ways to test a
# +windows_task+ resource with ChefSpec.
#
# @example Assert that a +windows_task+ was deleted
# expect(chef_run).to delete_windows_task('mytask')
#
#
# @param [String, Regex] resource_name
# the name of the resource to match
#
# @return [ChefSpec::Matchers::ResourceMatcher]
#
def delete_windows_task(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_task, :delete, resource_name)
end
#
# Assert that a +windows_task+ resource exists in the Chef run with the
# action +:run+. Given a Chef Recipe that runs "mytask" as a
# +windows_task+:
#
# windows_task 'mytask' do
# action :run
# end
#
# The Examples section demonstrates the different ways to test a
# +windows_task+ resource with ChefSpec.
#
# @example Assert that a +windows_task+ was run
# expect(chef_run).to run_windows_task('mytask')
#
#
# @param [String, Regex] resource_name
# the name of the resource to match
#
# @return [ChefSpec::Matchers::ResourceMatcher]
#
def run_windows_task(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_task, :run, resource_name)
end
#
# Assert that a +windows_task+ resource exists in the Chef run with the
# action +:change+. Given a Chef Recipe that changes "mytask" as a
# +windows_task+:
#
# windows_task 'mytask' do
# action :change
# end
#
# The Examples section demonstrates the different ways to test a
# +windows_task+ resource with ChefSpec.
#
# @example Assert that a +windows_task+ was changed
# expect(chef_run).to change_windows_task('mytask')
#
#
# @param [String, Regex] resource_name
# the name of the resource to match
#
# @return [ChefSpec::Matchers::ResourceMatcher]
#
def change_windows_task(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_task, :change, resource_name)
end
#
# Assert that a +windows_path+ resource exists in the Chef run with the
# action +:add+. Given a Chef Recipe that adds "C:\7-Zip" to the Windows
# PATH env var
#
# windows_path 'C:\7-Zip' do
# action :add
# end
#
# The Examples section demonstrates the different ways to test a
# +windows_path+ resource with ChefSpec.
#
# @example Assert that a +windows_path+ was added
# expect(chef_run).to add_windows_path('C:\7-Zip')
#
#
# @param [String, Regex] resource_name
# the name of the resource to match
#
# @return [ChefSpec::Matchers::ResourceMatcher]
#
def add_windows_path(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_path, :add, resource_name)
end
#
# Assert that a +windows_path+ resource exists in the Chef run with the
# action +:remove+. Given a Chef Recipe that removes "C:\7-Zip" from the
# Windows PATH env var
#
# windows_path 'C:\7-Zip' do
# action :remove
# end
#
# The Examples section demonstrates the different ways to test a
# +windows_path+ resource with ChefSpec.
#
# @example Assert that a +windows_path+ was removed
# expect(chef_run).to remove_windows_path('C:\7-Zip')
#
#
# @param [String, Regex] resource_name
# the name of the resource to match
#
# @return [ChefSpec::Matchers::ResourceMatcher]
#
def remove_windows_path(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_path, :remove, resource_name)
end
#
# Assert that a +windows_pagefile+ resource exists in the Chef run with the
# action +:set+. Given a Chef Recipe that sets a pagefile
#
# windows_pagefile "pagefile" do
# system_managed true
# initial_size 1024
# maximum_size 4096
# end
#
# The Examples section demonstrates the different ways to test a
# +windows_pagefile+ resource with ChefSpec.
#
# @example Assert that a +windows_pagefile+ was set
# expect(chef_run).to set_windows_pagefile('pagefile').with(
# initial_size: 1024)
#
#
# @param [String, Regex] resource_name
# the name of the resource to match
#
# @return [ChefSpec::Matchers::ResourceMatcher]
#
def set_windows_pagefile(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_pagefile, :set, resource_name)
end
#
# Assert that a +windows_zipfile+ resource exists in the Chef run with the
# action +:unzip+. Given a Chef Recipe that extracts "SysinternalsSuite.zip"
# to c:/bin
#
# windows_zipfile "c:/bin" do
# source "http://download.sysinternals.com/Files/SysinternalsSuite.zip"
# action :unzip
# not_if {::File.exists?("c:/bin/PsExec.exe")}
# end
#
# The Examples section demonstrates the different ways to test a
# +windows_zipfile+ resource with ChefSpec.
#
# @example Assert that a +windows_zipfile+ was unzipped
# expect(chef_run).to unzip_windows_zipfile_to('c:/bin')
#
#
# @param [String, Regex] resource_name
# the name of the resource to match
#
# @return [ChefSpec::Matchers::ResourceMatcher]
#
def unzip_windows_zipfile_to(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_zipfile, :unzip, resource_name)
end
#
# Assert that a +windows_zipfile+ resource exists in the Chef run with the
# action +:zip+. Given a Chef Recipe that zips "c:/src"
# to c:/code.zip
#
# windows_zipfile "c:/code.zip" do
# source "c:/src"
# action :zip
# end
#
# The Examples section demonstrates the different ways to test a
# +windows_zipfile+ resource with ChefSpec.
#
# @example Assert that a +windows_zipfile+ was zipped
# expect(chef_run).to zip_windows_zipfile_to('c:/code.zip')
#
#
# @param [String, Regex] resource_name
# the name of the resource to match
#
# @return [ChefSpec::Matchers::ResourceMatcher]
#
def zip_windows_zipfile_to(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_zipfile, :zip, resource_name)
end
#
# Assert that a +windows_share+ resource exists in the Chef run with the
# action +:create+. Given a Chef Recipe that shares "c:/src"
# as Src
#
# windows_share "Src" do
# path "c:/src"
# action :create
# end
#
# The Examples section demonstrates the different ways to test a
# +windows_share+ resource with ChefSpec.
#
# @example Assert that a +windows_share+ was created
# expect(chef_run).to create_windows_share('Src')
#
#
# @param [String, Regex] resource_name
# the name of the resource to match
#
# @return [ChefSpec::Matchers::ResourceMatcher]
#
def create_windows_share(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_share, :create, resource_name)
end
#
# Assert that a +windows_share+ resource exists in the Chef run with the
# action +:delete+. Given a Chef Recipe that deletes share "c:/src"
#
# windows_share "Src" do
# action :delete
# end
#
# The Examples section demonstrates the different ways to test a
# +windows_share+ resource with ChefSpec.
#
# @example Assert that a +windows_share+ was created
# expect(chef_run).to delete_windows_share('Src')
#
#
# @param [String, Regex] resource_name
# the name of the resource to match
#
# @return [ChefSpec::Matchers::ResourceMatcher]
#
def delete_windows_share(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_share, :delete, resource_name)
end
# All the other less commonly used LWRPs
def create_windows_shortcut(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_shortcut, :create, resource_name)
end
def create_windows_auto_run(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_auto_run, :create, resource_name)
end
def remove_windows_auto_run(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_auto_run, :remove, resource_name)
end
def create_windows_printer(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_printer, :create, resource_name)
end
def delete_windows_printer(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_printer, :delete, resource_name)
end
def create_windows_printer_port(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_printer_port, :create, resource_name)
end
def delete_windows_printer_port(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_printer_port, :delete, resource_name)
end
def install_windows_font(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_font, :install, resource_name)
end
def create_windows_certificate_binding(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_certificate_binding, :create, resource_name)
end
def delete_windows_certificate_binding(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_certificate_binding, :delete, resource_name)
end
def create_windows_http_acl(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_http_acl, :create, resource_name)
end
def delete_windows_http_acl(resource_name)
ChefSpec::Matchers::ResourceMatcher.new(:windows_http_acl, :delete, resource_name)
end
end

View File

@@ -1,9 +1,9 @@
#
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Cookbook:: windows
# Library:: helper
# Library:: powershell_helper
#
# Copyright:: 2011-2017, Chef Software, Inc.
# Copyright:: 2011-2018, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@@ -3,10 +3,10 @@
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Author:: Paul Morton (<pmorton@biaprotect.com>)
# Cookbook:: windows
# Provider:: registry
# Library:: registry_helper
#
# Copyright:: 2010-2017, VMware, Inc.
# Copyright:: 2011-2017, Chef Software, Inc.
# Copyright:: 2011-2018, Chef Software, Inc.
# Copyright:: 2011-2017, Business Intelligence Associates, Inc
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -45,7 +45,7 @@ module Windows
hkey = {
'HKLM' => 'HKEY_LOCAL_MACHINE',
'HKCU' => 'HKEY_CURRENT_USER',
'HKU' => 'HKEY_USERS',
'HKU' => 'HKEY_USERS',
}[hive_name] || hive_name
Chef::Log.debug("Hive resolved to #{hkey}")
@@ -257,9 +257,9 @@ module Windows
end
Chef::Log.debug("Resolved user SID to #{sid}")
return sid
sid
rescue
return nil
nil
end
def hive_loaded?(path)
@@ -350,7 +350,7 @@ module Windows
end
module Registry
module_function
module_function # rubocop: disable Lint/UselessAccessModifier
extend Windows::RegistryHelper
end

View File

@@ -3,7 +3,7 @@
# Cookbook:: windows
# Library:: version
#
# Copyright:: 2011-2017, Chef Software, Inc.
# Copyright:: 2011-2018, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -139,6 +139,7 @@ module Windows
end
WIN_VERSIONS = {
'Windows 10' => { major: 10, minor: 0, callable: -> { @product_type != VER_NT_WORKSTATION } },
'Windows Server 2012 R2' => { major: 6, minor: 3, callable: -> { @product_type != VER_NT_WORKSTATION } },
'Windows 8' => { major: 6, minor: 2, callable: -> { @product_type == VER_NT_WORKSTATION } },
'Windows Server 2012' => { major: 6, minor: 2, callable: -> { @product_type != VER_NT_WORKSTATION } },

View File

@@ -36,6 +36,20 @@ module Windows
STANDARD_SERVER = 0x0D unless constants.include?(:STANDARD_SERVER)
# Server Standard without Hyper-V Core
STANDARD_SERVER_V = 0x28 unless constants.include?(:STANDARD_SERVER_V)
# Small Business Server Premium Core
PRODUCT_SMALLBUSINESS_SERVER_PREMIUM_CORE = 0x3F unless constants.include?(:PRODUCT_SMALLBUSINESS_SERVER_PREMIUM_CORE)
# Server Solutions Premium Core
STANDARD_SERVER_SOLUTIONS = 0x35 unless constants.include?(:STANDARD_SERVER_SOLUTIONS)
# Storage Server Enterprise Core
STORAGE_ENTERPRISE_SERVER = 0x2E unless constants.include?(:STORAGE_ENTERPRISE_SERVER)
# Storage Server Express Core
STORAGE_EXPRESS_SERVER = 0x2B unless constants.include?(:STORAGE_EXPRESS_SERVER)
# Storage Server Standard Core
STORAGE_STANDARD_SERVER = 0x2C unless constants.include?(:STORAGE_STANDARD_SERVER)
# Storage Server Workgroup Core
STORAGE_WORKGROUP_SERVER = 0x2D unless constants.include?(:STORAGE_WORKGROUP_SERVER)
# Web Server Core
WEB_SERVER = 0x1D unless constants.include?(:WEB_SERVER)
end
# Module referencing product type contants
@@ -73,7 +87,7 @@ module Windows
end
def self.validate_platform(node)
raise 'Windows helper are only supported on windows platform!' if node['platform'] != 'windows'
raise 'Windows helper are only supported on windows platform!' unless node['platform'] == 'windows'
end
end
end

View File

@@ -1,9 +1,9 @@
#
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Cookbook:: windows
# Library:: helper
# Library:: windows_helper
#
# Copyright:: 2011-2017, Chef Software, Inc.
# Copyright:: 2011-2018, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -20,6 +20,9 @@
require 'uri'
require 'Win32API' if Chef::Platform.windows?
require 'chef/exceptions'
require 'openssl'
require 'chef/mixin/powershell_out'
require 'chef/util/path_helper'
module Windows
module Helper
@@ -30,6 +33,7 @@ module Windows
# returns windows friendly version of the provided path,
# ensures backslashes are used everywhere
def win_friendly_path(path)
Chef::Log.warn('The win_friendly_path helper has been deprecated and will be removed from the next major release of the windows cookbook. Please update any cookbooks using this helper to instead require `chef/util/path_helper` and then use `Chef::Util::PathHelper.cleanpath`.')
path.gsub(::File::SEPARATOR, ::File::ALT_SEPARATOR || '\\') if path
end
@@ -47,16 +51,6 @@ module Windows
end
end
# Create a feature provider dependent value object.
# mainly created becasue Windows Feature names are
# different based on whether dism.exe or servicemanagercmd.exe
# is used for installation
def value_for_feature_provider(provider_hash)
p = Chef::Platform.find_provider_for_node(node, :windows_feature)
key = p.to_s.downcase.split('::').last
provider_hash[key] || provider_hash[key.to_sym]
end
# singleton instance of the Windows Version checker
def win_version
@win_version ||= Windows::Version.new
@@ -88,7 +82,7 @@ module Windows
cache_file_path = source
end
windows_path ? win_friendly_path(cache_file_path) : cache_file_path
windows_path ? Chef::Util::PathHelper.cleanpath(cache_file_path) : cache_file_path
end
end
@@ -103,7 +97,7 @@ module Windows
buf.strip
end
def is_package_installed?(package_name) # rubocop:disable Style/PredicateName
def is_package_installed?(package_name) # rubocop:disable Naming/PredicateName
installed_packages.include?(package_name)
end

View File

@@ -57,7 +57,7 @@ class Chef
unless OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, token)
raise get_last_error
end
token = token.unpack('L')[0]
token = token.unpack1('L')
privileges.each do |name|
unless adjust_privilege(token, name, SE_PRIVILEGE_ENABLED)

View File

@@ -1,7 +1,9 @@
#
# Author:: Adam Edwards (<adamed@chef.io>)
# Cookbook:: windows
# Library:: wmi_helper
#
# Copyright:: 2014-2017, Chef Software, Inc.
# Copyright:: 2014-2018, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,11 @@
name 'windows'
maintainer 'Chef Software, Inc.'
maintainer_email 'cookbooks@chef.io'
license 'Apache-2.0'
description 'Provides a set of useful Windows-specific primitives.'
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
version '5.3.0'
supports 'windows'
source_url 'https://github.com/chef-cookbooks/windows'
issues_url 'https://github.com/chef-cookbooks/windows/issues'
chef_version '>= 13.4'

View File

@@ -0,0 +1,153 @@
#
# Author:: Richard Lavey (richard.lavey@calastone.com)
# Cookbook:: windows
# Provider:: dns
#
# Copyright:: 2015, Calastone Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# See this for info on DNSCMD
# https://technet.microsoft.com/en-gb/library/cc772069.aspx#BKMK_10
include Windows::Helper
# Support whyrun
def whyrun_supported?
true
end
action :create do
if @current_resource.exists
needs_change = (@new_resource.record_type != @current_resource.record_type) ||
(@new_resource.ttl > 0 && @new_resource.ttl != @current_resource.ttl) ||
(@new_resource.target.is_a?(String) && @new_resource.target != @current_resource.target) ||
(@new_resource.target.is_a?(Array) && !(@new_resource.target - @current_resource.target).empty?)
if needs_change
converge_by("Changing #{@new_resource.host_name}") do
update_dns
end
else
Chef::Log.debug("#{@new_resource.host_name} already exists - nothing to do")
end
else
converge_by("Creating #{@new_resource.host_name}") do
update_dns
end
end
end
action :delete do
if @current_resource.exists
converge_by("Deleting #{@current_resource.host_name}") do
execute_command! 'recorddelete', "#{@current_resource.record_type} /f"
end
else
Chef::Log.debug("#{@new_resource.host_name} does not exist - nothing to do")
end
end
def load_current_resource
# validate the new resource params : A records should be an array
if @new_resource.record_type == 'A' && @new_resource.target.is_a?(String)
raise 'target property must be an array for record_type A'
end
@current_resource = Chef::Resource::WindowsDns.new(@new_resource.name)
@current_resource.host_name(@new_resource.host_name)
@current_resource.dns_server(@new_resource.dns_server)
parts = @current_resource.host_name.scan(/(\w+)\.(.*)/)
@host = parts[0][0]
@domain = parts[0][1]
fetch_attributes
end
private
def fetch_attributes
@command = locate_sysnative_cmd('dnscmd.exe')
cmd = shell_out("#{@command} #{@current_resource.dns_server} /enumrecords #{@domain} #{@host}")
Chef::Log.debug "dnscmd reports: #{cmd.stdout}"
# extract values from returned text
if cmd.stdout.include?('DNS_ERROR_NAME_DOES_NOT_EXIST')
@current_resource.exists = false
@current_resource.target([])
elsif cmd.exitstatus == 0
@current_resource.exists = true
m = cmd.stdout.scan(/(\d+)\s(A)\s+(\d+\.\d+\.\d+\.\d+)/)
if m.empty?
m = cmd.stdout.scan(/(\d+)\s(CNAME)\s+((?:\w+\.)+)/)
if m.empty?
@current_resource.exists = false
@current_resource.target([])
else
# We have a cname record
@current_resource.record_type('CNAME')
@current_resource.ttl(m[0][0].to_i)
@current_resource.target(m[0][2].chomp('.'))
end
else
# we have A entries
@current_resource.record_type('A')
@current_resource.ttl(m[0][0].to_i)
addresses = []
m.each do |match|
addresses.push(match[2])
end
@current_resource.target(addresses)
end
else
raise "dnscmd returned error #{cmd.exitstatus} : #{cmd.stderr} #{cmd.stdout}"
end
end
def update_dns
ttl = @new_resource.ttl if @new_resource.ttl > 0
if @current_resource.record_type != @new_resource.record_type
# delete current record(s) as we're changing the type
execute_command! 'recorddelete', "#{@current_resource.record_type} /f"
end
if @new_resource.record_type == 'A'
# delete existing records that are no longer defined
(@current_resource.target - @new_resource.target).each do |address|
Chef::Log.info "Deleting #{address}"
execute_command! 'recorddelete', "A #{address} /f"
end
# add new records that don't exist
# if ttl has changed then update all records
addresses = if @current_resource.ttl == @new_resource.ttl
(@new_resource.target - @current_resource.target)
else
@new_resource.target
end
addresses.each do |address|
Chef::Log.info "Adding/Changing #{address}"
execute_command! 'recordadd', "#{ttl} A #{address}"
end
else
execute_command! 'recordadd', "#{ttl} CNAME #{@new_resource.target}"
end
end
def execute_command!(mode, options)
shell_out!("#{@command} #{@current_resource.dns_server} /#{mode} #{@domain} #{@host} #{options}")
end

View File

@@ -3,7 +3,7 @@
# Cookbook:: windows
# Recipe:: default
#
# Copyright:: 2011-2017, Chef Software, Inc.
# Copyright:: 2011-2018, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@@ -3,8 +3,8 @@
# Cookbook:: windows
# Resource:: auto_run
#
# Copyright:: 2011-2017, Business Intelligence Associates, Inc.
# Copyright:: 2017, Chef Software, Inc.
# Copyright:: 2011-2018, Business Intelligence Associates, Inc.
# Copyright:: 2017-2018, Chef Software Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -19,28 +19,48 @@
# limitations under the License.
#
property :program, String
property :name, String, name_property: true
chef_version_for_provides '< 14.0' if respond_to?(:chef_version_for_provides)
resource_name :windows_auto_run
property :program_name, String, name_property: true
property :path, String, coerce: proc { |x| x.tr('/', '\\') }
property :args, String
property :root, Symbol,
equal_to: %i(machine user),
default: :machine
alias_method :program, :path
action :create do
registry_key 'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run' do
data = "\"#{new_resource.path}\""
data << " #{new_resource.args}" if new_resource.args
registry_key registry_path do
values [{
name: new_resource.name,
name: new_resource.program_name,
type: :string,
data: "\"#{new_resource.program}\" #{new_resource.args}",
data: data,
}]
action :create
end
end
action :remove do
registry_key 'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run' do
registry_key registry_path do
values [{
name: new_resource.name,
name: new_resource.program_name,
type: :string,
data: '',
}]
action :delete
end
end
action_class do
# determine the full registry path based on the root property
# @return [String]
def registry_path
{ machine: 'HKLM', user: 'HKCU' }[new_resource.root] + \
'\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run'
end
end

View File

@@ -4,6 +4,7 @@
# Resource:: certificate
#
# Copyright:: 2015-2017, Calastone Ltd.
# Copyright:: 2018-2019, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -18,29 +19,38 @@
# limitations under the License.
#
include Windows::Helper
require 'chef/util/path_helper'
property :source, String, name_property: true, required: true
chef_version_for_provides '< 14.7' if respond_to?(:chef_version_for_provides)
resource_name :windows_certificate
property :source, String, name_property: true
property :pfx_password, String
property :private_key_acl, Array
property :store_name, String, default: 'MY', regex: /^(?:MY|CA|ROOT|TrustedPublisher|TRUSTEDPEOPLE)$/
property :user_store, [true, false], default: false
property :store_name, String, default: 'MY', equal_to: ['TRUSTEDPUBLISHER', 'TrustedPublisher', 'CLIENTAUTHISSUER', 'REMOTE DESKTOP', 'ROOT', 'TRUSTEDDEVICES', 'WEBHOSTING', 'CA', 'AUTHROOT', 'TRUSTEDPEOPLE', 'MY', 'SMARTCARDROOT', 'TRUST', 'DISALLOWED']
property :user_store, [TrueClass, FalseClass], default: false
property :cert_path, String
property :sensitive, [ TrueClass, FalseClass ], default: lazy { |r| r.pfx_password ? true : false }
action :create do
hash = '$cert.GetCertHashString()'
code_script = cert_script(true) <<
within_store_script { |store| store + '.Add($cert)' } <<
acl_script(hash)
load_gem
guard_script = cert_script(false) <<
cert_exists_script(hash)
# Extension of the certificate
ext = ::File.extname(new_resource.source)
cert_obj = fetch_cert_object(ext) # Fetch OpenSSL::X509::Certificate object
thumbprint = OpenSSL::Digest::SHA1.new(cert_obj.to_der).to_s # Fetch its thumbprint
converge_by("adding certificate #{new_resource.source} into #{new_resource.store_name} to #{cert_location}\\#{new_resource.store_name}") do
powershell_script new_resource.name do
guard_interpreter :powershell_script
convert_boolean_return true
code code_script
not_if guard_script
# Need to check if return value is Boolean:true
# If not then the given certificate should be added in certstore
if verify_cert(thumbprint) == true
Chef::Log.debug('Certificate is already present')
else
converge_by("Adding certificate #{new_resource.source} into Store #{new_resource.store_name}") do
if ext == '.pfx'
add_pfx_cert
else
add_cert(cert_obj)
end
end
end
end
@@ -60,59 +70,146 @@ action :acl_add do
code_script << acl_script(hash)
guard_script << cert_exists_script(hash)
converge_by("setting the acls on #{new_resource.source} in #{cert_location}\\#{new_resource.store_name}") do
powershell_script new_resource.name do
guard_interpreter :powershell_script
convert_boolean_return true
code code_script
only_if guard_script
end
powershell_script "setting the acls on #{new_resource.source} in #{cert_location}\\#{new_resource.store_name}" do
guard_interpreter :powershell_script
convert_boolean_return true
code code_script
only_if guard_script
sensitive if new_resource.sensitive
end
end
action :delete do
# do we have a hash or a subject?
# TODO: It's a bit annoying to know the thumbprint of a cert you want to remove when you already
# have the file. Support reading the hash directly from the file if provided.
search = if new_resource.source =~ /^[a-fA-F0-9]{40}$/
"Thumbprint -eq '#{new_resource.source}'"
else
"Subject -like '*#{new_resource.source.sub(/\*/, '`*')}*'" # escape any * in the source
end
cert_command = "Get-ChildItem Cert:\\#{cert_location}\\#{new_resource.store_name} | where { $_.#{search} }"
load_gem
code_script = within_store_script do |store|
<<-EOH
foreach ($c in #{cert_command})
{
#{store}.Remove($c)
}
EOH
end
guard_script = "@(#{cert_command}).Count -gt 0\n"
converge_by("Removing certificate #{new_resource.source} from #{cert_location}\\#{new_resource.store_name}") do
powershell_script new_resource.name do
guard_interpreter :powershell_script
convert_boolean_return true
code code_script
only_if guard_script
cert_obj = fetch_cert
if cert_obj
converge_by("Deleting certificate #{new_resource.source} from Store #{new_resource.store_name}") do
delete_cert
end
else
Chef::Log.debug('Certificate not found')
end
end
action :fetch do
load_gem
cert_obj = fetch_cert
if cert_obj
show_or_store_cert(cert_obj)
else
Chef::Log.debug('Certificate not found')
end
end
action :verify do
load_gem
out = verify_cert
if !!out == out
out = out ? 'Certificate is valid' : 'Certificate not valid'
end
Chef::Log.info(out.to_s)
end
action_class do
require 'openssl'
# load the gem and rescue a gem install if it fails to load
def load_gem
gem 'win32-certstore', '>= 0.2.4'
require 'win32-certstore' # until this is in core chef
rescue LoadError
Chef::Log.debug('Did not find win32-certstore >= 0.2.4 gem installed. Installing now')
chef_gem 'win32-certstore' do
compile_time true
action :upgrade
end
require 'win32-certstore'
end
def add_cert(cert_obj)
store = ::Win32::Certstore.open(new_resource.store_name)
store.add(cert_obj)
end
def add_pfx_cert
store = ::Win32::Certstore.open(new_resource.store_name)
store.add_pfx(new_resource.source, new_resource.pfx_password)
end
def delete_cert
store = ::Win32::Certstore.open(new_resource.store_name)
store.delete(new_resource.source)
end
def fetch_cert
store = ::Win32::Certstore.open(new_resource.store_name)
store.get(new_resource.source)
end
# Checks whether a certificate with the given thumbprint
# is already present and valid in certificate store
# If the certificate is not present, verify_cert returns a String: "Certificate not found"
# But if it is present but expired, it returns a Boolean: false
# Otherwise, it returns a Boolean: true
def verify_cert(thumbprint = new_resource.source)
store = ::Win32::Certstore.open(new_resource.store_name)
store.valid?(thumbprint)
end
def show_or_store_cert(cert_obj)
if new_resource.cert_path
export_cert(cert_obj, new_resource.cert_path)
if ::File.size(new_resource.cert_path) > 0
Chef::Log.info("Certificate export in #{new_resource.cert_path}")
else
::File.delete(new_resource.cert_path)
end
else
Chef::Log.info(cert_obj.display)
end
end
def export_cert(cert_obj, cert_path)
out_file = ::File.new(cert_path, 'w+')
case ::File.extname(cert_path)
when '.pem'
out_file.puts(cert_obj.to_pem)
when '.der'
out_file.puts(cert_obj.to_der)
when '.cer'
cert_out = powershell_out("openssl x509 -text -inform DER -in #{cert_obj.to_pem} -outform CER").stdout
out_file.puts(cert_out)
when '.crt'
cert_out = powershell_out("openssl x509 -text -inform DER -in #{cert_obj.to_pem} -outform CRT").stdout
out_file.puts(cert_out)
when '.pfx'
cert_out = powershell_out("openssl pkcs12 -export -nokeys -in #{cert_obj.to_pem} -outform PFX").stdout
out_file.puts(cert_out)
when '.p7b'
cert_out = powershell_out("openssl pkcs7 -export -nokeys -in #{cert_obj.to_pem} -outform P7B").stdout
out_file.puts(cert_out)
else
Chef::Log.info('Supported certificate format .pem, .der, .cer, .crt, .pfx and .p7b')
end
out_file.close
end
def cert_location
@location ||= new_resource.user_store ? 'CurrentUser' : 'LocalMachine'
end
def cert_script(persist)
cert_script = '$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2'
file = win_friendly_path(new_resource.source)
file = Chef::Util::PathHelper.cleanpath(new_resource.source)
cert_script << " \"#{file}\""
if ::File.extname(file.downcase) == '.pfx'
cert_script << ", \"#{new_resource.pfx_password}\""
if persist && new_resource.user_store
cert_script << ', [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::PersistKeySet'
cert_script << ', ([System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::PersistKeySet)'
elsif persist
cert_script << ', ([System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::PersistKeySet -bor [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::MachineKeyset)'
end
@@ -122,45 +219,83 @@ action_class do
def cert_exists_script(hash)
<<-EOH
$hash = #{hash}
Test-Path "Cert:\\#{cert_location}\\#{new_resource.store_name}\\$hash"
EOH
$hash = #{hash}
Test-Path "Cert:\\#{cert_location}\\#{new_resource.store_name}\\$hash"
EOH
end
def within_store_script
inner_script = yield '$store'
<<-EOH
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store "#{new_resource.store_name}", ([System.Security.Cryptography.X509Certificates.StoreLocation]::#{cert_location})
$store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)
#{inner_script}
$store.Close()
EOH
$store = New-Object System.Security.Cryptography.X509Certificates.X509Store "#{new_resource.store_name}", ([System.Security.Cryptography.X509Certificates.StoreLocation]::#{cert_location})
$store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)
#{inner_script}
$store.Close()
EOH
end
def acl_script(hash)
return '' if new_resource.private_key_acl.nil? || new_resource.private_key_acl.empty?
# this PS came from http://blogs.technet.com/b/operationsguy/archive/2010/11/29/provide-access-to-private-keys-commandline-vs-powershell.aspx
# and from https://msdn.microsoft.com/en-us/library/windows/desktop/bb204778(v=vs.85).aspx
set_acl_script = <<-EOH
$hash = #{hash}
$storeCert = Get-ChildItem "cert:\\#{cert_location}\\#{new_resource.store_name}\\$hash"
if ($storeCert -eq $null) { throw 'no key exists.' }
$keyname = $storeCert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName
if ($keyname -eq $null) { throw 'no private key exists.' }
if ($storeCert.PrivateKey.CspKeyContainerInfo.MachineKeyStore)
{
$fullpath = "$Env:ProgramData\\Microsoft\\Crypto\\RSA\\MachineKeys\\$keyname"
}
else
{
$currentUser = New-Object System.Security.Principal.NTAccount($Env:UserDomain, $Env:UserName)
$userSID = $currentUser.Translate([System.Security.Principal.SecurityIdentifier]).Value
$fullpath = "$Env:ProgramData\\Microsoft\\Crypto\\RSA\\$userSID\\$keyname"
}
EOH
$hash = #{hash}
$storeCert = Get-ChildItem "cert:\\#{cert_location}\\#{new_resource.store_name}\\$hash"
if ($storeCert -eq $null) { throw 'no key exists.' }
$keyname = $storeCert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName
if ($keyname -eq $null) { throw 'no private key exists.' }
if ($storeCert.PrivateKey.CspKeyContainerInfo.MachineKeyStore)
{
$fullpath = "$Env:ProgramData\\Microsoft\\Crypto\\RSA\\MachineKeys\\$keyname"
}
else
{
$currentUser = New-Object System.Security.Principal.NTAccount($Env:UserDomain, $Env:UserName)
$userSID = $currentUser.Translate([System.Security.Principal.SecurityIdentifier]).Value
$fullpath = "$Env:ProgramData\\Microsoft\\Crypto\\RSA\\$userSID\\$keyname"
}
EOH
new_resource.private_key_acl.each do |name|
set_acl_script << "$uname='#{name}'; icacls $fullpath /grant $uname`:RX\n"
end
set_acl_script
end
# Method returns an OpenSSL::X509::Certificate object
#
# Based on its extension, the certificate contents are used to initialize
# PKCS12 (PFX), PKCS7 (P7B) objects which contains OpenSSL::X509::Certificate.
#
# @note Other then PEM, all the certificates are usually in binary format, and hence
# their contents are loaded by using File.binread
#
# @param ext [String] Extension of the certificate
#
# @return [OpenSSL::X509::Certificate] Object containing certificate's attributes
#
# @raise [OpenSSL::PKCS12::PKCS12Error] When incorrect password is provided for PFX certificate
#
def fetch_cert_object(ext)
contents = if binary_cert?
::File.binread(new_resource.source)
else
::File.read(new_resource.source)
end
case ext
when '.pfx'
OpenSSL::PKCS12.new(contents, new_resource.pfx_password).certificate
when '.p7b'
OpenSSL::PKCS7.new(contents).certificates.first
else
OpenSSL::X509::Certificate.new(contents)
end
end
# @return [Boolean] Whether the certificate file is binary encoded or not
#
def binary_cert?
powershell_out!("file -b --mime-encoding #{new_resource.source}").stdout.strip == 'binary'
end
end

View File

@@ -4,6 +4,7 @@
# Resource:: certificate_binding
#
# Copyright:: 2015-2017, Calastone Ltd.
# Copyright:: 2018, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -18,20 +19,20 @@
# limitations under the License.
#
include Chef::Mixin::ShellOut
include Chef::Mixin::PowershellOut
include Windows::Helper
property :cert_name, String, name_property: true, required: true
property :cert_name, String, name_property: true
property :name_kind, Symbol, equal_to: [:hash, :subject], default: :subject
property :address, String, default: '0.0.0.0'
property :port, Integer, default: 443
property :app_id, String, default: '{4dc3e181-e14b-4a21-b022-59fc669b0914}'
property :store_name, String, default: 'MY', regex: /^(?:MY|CA|ROOT)$/
property :store_name, String, default: 'MY', equal_to: ['TRUSTEDPUBLISHER', 'CLIENTAUTHISSUER', 'REMOTE DESKTOP', 'ROOT', 'TRUSTEDDEVICES', 'WEBHOSTING', 'CA', 'AUTHROOT', 'TRUSTEDPEOPLE', 'MY', 'SMARTCARDROOT', 'TRUST']
property :exists, [true, false], desired_state: true
load_current_value do |desired|
cmd = shell_out("#{locate_sysnative_cmd('netsh.exe')} http show sslcert ipport=#{desired.address}:#{desired.port}")
mode = desired.address.match(/(\d+\.){3}\d+|\[.+\]/).nil? ? 'hostnameport' : 'ipport'
cmd = shell_out("#{locate_sysnative_cmd('netsh.exe')} http show sslcert #{mode}=#{desired.address}:#{desired.port}")
Chef::Log.debug "netsh reports: #{cmd.stdout}"
address desired.address
@@ -88,7 +89,8 @@ action_class do
def add_binding(hash)
cmd = "#{netsh_command} http add sslcert"
cmd << " ipport=#{current_resource.address}:#{current_resource.port}"
mode = address_mode(current_resource.address)
cmd << " #{mode}=#{current_resource.address}:#{current_resource.port}"
cmd << " certhash=#{hash}"
cmd << " appid=#{current_resource.app_id}"
cmd << " certstorename=#{current_resource.store_name}"
@@ -98,7 +100,8 @@ action_class do
end
def delete_binding
shell_out!("#{netsh_command} http delete sslcert ipport=#{current_resource.address}:#{current_resource.port}")
mode = address_mode(current_resource.address)
shell_out!("#{netsh_command} http delete sslcert #{mode}=#{current_resource.address}:#{current_resource.port}")
end
def check_hash(hash)
@@ -125,4 +128,8 @@ action_class do
hash = p.stdout.strip
hash[0].ord == 239 ? hash.force_encoding('UTF-8').delete!("\xEF\xBB\xBF".force_encoding('UTF-8')) : hash
end
def address_mode(address)
address.match(/(\d+\.){3}\d+|\[.+\]/).nil? ? 'hostnameport' : 'ipport'
end
end

View File

@@ -1,9 +1,9 @@
#
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Cookbook:: windows
# Attribute:: default
# Author:: Richard Lavey (richard.lavey@calastone.com)
# Cookbook Name:: windows
# Resource:: dns
#
# Copyright:: 2011-2017, Chef Software, Inc
# Copyright:: 2015, Calastone Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -18,4 +18,13 @@
# limitations under the License.
#
default['windows']['rubyzipversion'] = nil
actions :create, :delete
default_action :create
attribute :host_name, kind_of: String, name_property: true, required: true
attribute :record_type, kind_of: String, default: 'A', regex: /^(?:A|CNAME)$/
attribute :dns_server, kind_of: String, default: '.'
attribute :target, kind_of: [Array, String], required: true
attribute :ttl, kind_of: Integer, required: false, default: 0
attr_accessor :exists

View File

@@ -3,7 +3,7 @@
# Cookbook:: windows
# Resource:: feature
#
# Copyright:: 2011-2017, Chef Software, Inc.
# Copyright:: 2011-2018, Chef Software Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -18,65 +18,42 @@
# limitations under the License.
#
chef_version_for_provides '< 14.0' if respond_to?(:chef_version_for_provides)
resource_name :windows_feature
property :feature_name, [Array, String], name_property: true
property :source, String
property :all, [true, false], default: false
property :management_tools, [true, false], default: false
property :install_method, Symbol, equal_to: [:windows_feature_dism, :windows_feature_powershell, :windows_feature_servermanagercmd]
include Windows::Helper
def whyrun_supported?
true
end
property :timeout, Integer, default: 600
action :install do
run_default_provider :install
run_default_subresource :install
end
action :remove do
run_default_provider :remove
run_default_subresource :remove
end
action :delete do
run_default_provider :delete
run_default_subresource :delete
end
action_class do
def locate_default_provider
if new_resource.install_method
new_resource.install_method
elsif ::File.exist?(locate_sysnative_cmd('dism.exe'))
:windows_feature_dism
elsif ::File.exist?(locate_sysnative_cmd('servermanagercmd.exe'))
:windows_feature_servermanagercmd
else
:windows_feature_powershell
end
end
# call the appropriate windows_feature resource based on the specified subresource
# @return [void]
def run_default_subresource(desired_action)
raise 'Support for Windows feature installation via servermanagercmd.exe has been removed as this support is no longer needed in Windows 2008 R2 and above. You will need to update your cookbook to install either via dism or powershell (preferred).' if new_resource.install_method == :windows_feature_servermanagercmd
def run_default_provider(desired_action)
case locate_default_provider
when :windows_feature_dism
windows_feature_dism new_resource.name do
action desired_action
feature_name new_resource.feature_name
source new_resource.source if new_resource.source
all new_resource.all
end
when :windows_feature_servermanagercmd
windows_feature_servermanagercmd new_resource.name do
action desired_action
feature_name new_resource.feature_name
source new_resource.source if new_resource.source
all new_resource.all
end
when :windows_feature_powershell
windows_feature_powershell new_resource.name do
action desired_action
feature_name new_resource.feature_name
source new_resource.source if new_resource.source
all new_resource.all
end
subresource = new_resource.install_method || :windows_feature_dism
declare_resource(subresource, new_resource.name) do
action desired_action
feature_name new_resource.feature_name
source new_resource.source if new_resource.source
all new_resource.all
timeout new_resource.timeout
management_tools new_resource.management_tools if subresource == :windows_feature_powershell
end
end
end

View File

@@ -1,9 +1,9 @@
#
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Cookbook:: windows
# Provider:: feature_dism
# Resource:: feature_dism
#
# Copyright:: 2011-2017, Chef Software, Inc.
# Copyright:: 2011-2018, Chef Software Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -18,87 +18,191 @@
# limitations under the License.
#
property :feature_name, [Array, String], name_property: true
chef_version_for_provides '< 14.0' if respond_to?(:chef_version_for_provides)
resource_name :windows_feature_dism
property :feature_name, [Array, String], coerce: proc { |x| to_formatted_array(x) }, name_property: true
property :source, String
property :all, [true, false], default: false
property :timeout, Integer, default: 600
# @return [Array] lowercase the array unless we're on < Windows 2012
def to_formatted_array(x)
x = x.split(/\s*,\s*/) if x.is_a?(String) # split multiple forms of a comma separated list
# feature installs on windows < 2012 are case sensitive so only downcase when on 2012+
# @todo when we're really ready to remove support for Windows 2008 R2 this check can go away
older_than_2012_or_8? ? x : x.map(&:downcase)
end
# a simple helper to determine if we're on a windows release pre-2012 / 8
# @return [Boolean] Is the system older than Windows 8 / 2012
def older_than_2012_or_8?
node['platform_version'].to_f < 6.2
end
include Chef::Mixin::ShellOut
include Windows::Helper
action :install do
Chef::Log.warn("Requested feature #{new_resource.feature_name} is not available on this system.") unless available?
unless !available? || installed?
converge_by("install Windows feature #{new_resource.feature_name}") do
addsource = new_resource.source ? "/LimitAccess /Source:\"#{new_resource.source}\"" : ''
addall = new_resource.all ? '/All' : ''
shell_out!("#{dism} /online /enable-feature #{to_array(new_resource.feature_name).map { |feature| "/featurename:#{feature}" }.join(' ')} /norestart #{addsource} #{addall}", returns: [0, 42, 127, 3010])
# Reload ohai data
reload_ohai_features_plugin(new_resource.action, new_resource.feature_name)
reload_cached_dism_data unless node['dism_features_cache']
fail_if_unavailable # fail if the features don't exist
Chef::Log.debug("Windows features needing installation: #{features_to_install.empty? ? 'none' : features_to_install.join(',')}")
unless features_to_install.empty?
message = "install Windows feature#{'s' if features_to_install.count > 1} #{features_to_install.join(',')}"
converge_by(message) do
install_command = "#{dism} /online /enable-feature #{features_to_install.map { |f| "/featurename:#{f}" }.join(' ')} /norestart"
install_command << " /LimitAccess /Source:\"#{new_resource.source}\"" if new_resource.source
install_command << ' /All' if new_resource.all
begin
shell_out!(install_command, returns: [0, 42, 127, 3010], timeout: new_resource.timeout)
rescue Mixlib::ShellOut::ShellCommandFailed => e
raise "Error 50 returned by DISM related to parent features, try setting the 'all' property to 'true' on the 'windows_feature_dism' resource." if required_parent_feature?(e.inspect)
raise e.message
end
reload_cached_dism_data # Reload cached dism feature state
end
end
end
action :remove do
if installed?
converge_by("removing Windows feature #{new_resource.feature_name}") do
shell_out!("#{dism} /online /disable-feature #{to_array(new_resource.feature_name).map { |feature| "/featurename:#{feature}" }.join(' ')} /norestart", returns: [0, 42, 127, 3010])
# Reload ohai data
reload_ohai_features_plugin(new_resource.action, new_resource.feature_name)
reload_cached_dism_data unless node['dism_features_cache']
Chef::Log.debug("Windows features needing removal: #{features_to_remove.empty? ? 'none' : features_to_remove.join(',')}")
unless features_to_remove.empty?
message = "remove Windows feature#{'s' if features_to_remove.count > 1} #{features_to_remove.join(',')}"
converge_by(message) do
shell_out!("#{dism} /online /disable-feature #{features_to_remove.map { |f| "/featurename:#{f}" }.join(' ')} /norestart", returns: [0, 42, 127, 3010], timeout: new_resource.timeout)
reload_cached_dism_data # Reload cached dism feature state
end
end
end
action :delete do
raise Chef::Exceptions::UnsupportedAction, "#{self} :delete action not support on #{win_version.sku}" unless supports_feature_delete?
if available?
converge_by("deleting Windows feature #{new_resource.feature_name} from the image") do
shell_out!("#{dism} /online /disable-feature #{to_array(new_resource.feature_name).map { |feature| "/featurename:#{feature}" }.join(' ')} /Remove /norestart", returns: [0, 42, 127, 3010])
# Reload ohai data
reload_ohai_features_plugin(new_resource.action, new_resource.feature_name)
raise_if_delete_unsupported
reload_cached_dism_data unless node['dism_features_cache']
fail_if_unavailable # fail if the features don't exist
Chef::Log.debug("Windows features needing deletion: #{features_to_delete.empty? ? 'none' : features_to_delete.join(',')}")
unless features_to_delete.empty?
message = "delete Windows feature#{'s' if features_to_delete.count > 1} #{features_to_delete.join(',')} from the image"
converge_by(message) do
shell_out!("#{dism} /online /disable-feature #{features_to_delete.map { |f| "/featurename:#{f}" }.join(' ')} /Remove /norestart", returns: [0, 42, 127, 3010], timeout: new_resource.timeout)
reload_cached_dism_data # Reload cached dism feature state
end
end
end
action_class do
def installed?
@installed ||= begin
install_ohai_plugin unless node['dism_features']
# @return [Array] features the user has requested to install which need installation
def features_to_install
@install ||= begin
# disabled features are always available to install
available_for_install = node['dism_features_cache']['disabled'].dup
# Compare against ohai plugin instead of costly dism run
node['dism_features'].key?(new_resource.feature_name) && node['dism_features'][new_resource.feature_name] =~ /Enable/
# removed features are also available for installation
available_for_install.concat(node['dism_features_cache']['removed'])
# the intersection of the features to install & disabled/removed features are what needs installing
new_resource.feature_name & available_for_install
end
end
def available?
@available ||= begin
install_ohai_plugin unless node['dism_features']
# @return [Array] features the user has requested to remove which need removing
def features_to_remove
# the intersection of the features to remove & enabled features are what needs removing
@remove ||= new_resource.feature_name & node['dism_features_cache']['enabled']
end
# Compare against ohai plugin instead of costly dism run
node['dism_features'].key?(new_resource.feature_name) && node['dism_features'][new_resource.feature_name] !~ /with payload removed/
# @return [Array] features the user has requested to delete which need deleting
def features_to_delete
# the intersection of the features to remove & enabled/disabled features are what needs removing
@remove ||= begin
all_available = node['dism_features_cache']['enabled'] +
node['dism_features_cache']['disabled']
new_resource.feature_name & all_available
end
end
def reload_ohai_features_plugin(take_action, feature_name)
ohai "Reloading Dism_Features Plugin - Action #{take_action} of feature #{feature_name}" do
action :reload
plugin 'dism_features'
# if any features are not supported on this release of Windows or
# have been deleted raise with a friendly message. At one point in time
# we just warned, but this goes against the behavior of ever other package
# provider in Chef and it isn't clear what you'd want if you passed an array
# and some features were available and others were not.
# @return [void]
def fail_if_unavailable
all_available = node['dism_features_cache']['enabled'] +
node['dism_features_cache']['disabled'] +
node['dism_features_cache']['removed']
# the difference of desired features to install to all features is what's not available
unavailable = (new_resource.feature_name - all_available)
raise "The Windows feature#{'s' if unavailable.count > 1} #{unavailable.join(',')} #{unavailable.count > 1 ? 'are' : 'is'} not available on this version of Windows. Run 'dism /online /Get-Features' to see the list of available feature names." unless unavailable.empty?
end
# run dism.exe to get a list of all available features and their state
# and save that to the node at node.override level.
# We do this because getting a list of features in dism takes at least a second
# and this data will be persisted across multiple resource runs which gives us
# a much faster run when no features actually need to be installed / removed.
# @return [void]
def reload_cached_dism_data
Chef::Log.debug('Caching Windows features available via dism.exe.')
node.override['dism_features_cache'] = Mash.new
node.override['dism_features_cache']['enabled'] = []
node.override['dism_features_cache']['disabled'] = []
node.override['dism_features_cache']['removed'] = []
# Grab raw feature information from dism command line
raw_list_of_features = shell_out("#{dism} /Get-Features /Online /Format:Table /English").stdout
# Split stdout into an array by windows line ending
features_list = raw_list_of_features.split("\r\n")
features_list.each do |feature_details_raw|
case feature_details_raw
when /Payload Removed/ # matches 'Disabled with Payload Removed'
add_to_feature_mash('removed', feature_details_raw)
when /Enable/ # matches 'Enabled' and 'Enable Pending' aka after reboot
add_to_feature_mash('enabled', feature_details_raw)
when /Disable/ # matches 'Disabled' and 'Disable Pending' aka after reboot
add_to_feature_mash('disabled', feature_details_raw)
end
end
Chef::Log.debug("The dism cache contains\n#{node['dism_features_cache']}")
end
def install_ohai_plugin
Chef::Log.info("node['dism_features'] data missing. Installing the dism_features Ohai plugin")
# parse the feature string and add the values to the appropriate array
# in the
# strips trailing whitespace characters then split on n number of spaces
# + | + n number of spaces
# @return [void]
def add_to_feature_mash(feature_type, feature_string)
feature_details = feature_string.strip.split(/\s+[|]\s+/).first
ohai_plugin 'dism_features' do
compile_time true
cookbook 'windows'
end
# dism on windows 2012+ isn't case sensitive so it's best to compare
# lowercase lists so the user input doesn't need to be case sensitive
# @todo when we're ready to remove windows 2008R2 the gating here can go away
feature_details.downcase! unless older_than_2012_or_8?
node.override['dism_features_cache'][feature_type] << feature_details
end
def supports_feature_delete?
win_version.major_version >= 6 && win_version.minor_version >= 2
# Fail unless we're on windows 8+ / 2012+ where deleting a feature is supported
# @return [void]
def raise_if_delete_unsupported
raise Chef::Exceptions::UnsupportedAction, "#{self} :delete action not support on Windows releases before Windows 8/2012. Cannot continue!" if older_than_2012_or_8?
end
# account for File System Redirector
def required_parent_feature?(error_message)
error_message.include?('Error: 50') && error_message.include?('required parent feature')
end
# find dism accounting for File System Redirector
# http://msdn.microsoft.com/en-us/library/aa384187(v=vs.85).aspx
def dism
@dism ||= begin

View File

@@ -1,70 +1,242 @@
#
# Author:: Greg Zapp (<greg.zapp@gmail.com>)
# Cookbook:: windows
# Provider:: feature_powershell
# Resource:: feature_powershell
#
# Copyright:: 2015-2018, Chef Software, Inc
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
property :feature_name, [Array, String], name_attribute: true
require 'chef/json_compat'
chef_version_for_provides '< 14.0' if respond_to?(:chef_version_for_provides)
resource_name :windows_feature_powershell
property :feature_name, [Array, String], coerce: proc { |x| to_formatted_array(x) }, name_property: true
property :source, String
property :all, [true, false], default: false
property :all, [TrueClass, FalseClass], default: false
property :timeout, Integer, default: 600
property :management_tools, [TrueClass, FalseClass], default: false
# a simple helper to determine if we're on a windows release pre-2012 / 8
# @return [Boolean] Is the system older than Windows 8 / 2012
def older_than_2012_or_8?
node['platform_version'].to_f < 6.2
end
def to_formatted_array(x)
x = x.split(/\s*,\s*/) if x.is_a?(String) # split multiple forms of a comma separated list
# feature installs on windows < 8/2012 are case sensitive so only downcase when on 2012+
older_than_2012_or_8? ? x : x.map(&:downcase)
end
include Chef::Mixin::PowershellOut
include Windows::Helper
action :install do
raise_on_old_powershell
reload_cached_powershell_data unless node['powershell_features_cache']
fail_if_unavailable # fail if the features don't exist
fail_if_removed # fail if the features are in removed state
Chef::Log.debug("Windows features needing installation: #{features_to_install.empty? ? 'none' : features_to_install.join(',')}")
unless features_to_install.empty?
converge_by("install Windows feature#{'s' if features_to_install.count > 1} #{features_to_install.join(',')}") do
install_command = "#{install_feature_cmdlet} #{features_to_install.join(',')}"
install_command << ' -IncludeAllSubFeature' if new_resource.all
if older_than_2012_or_8? && (new_resource.source || new_resource.management_tools)
Chef::Log.warn("The 'source' and 'management_tools' properties are only available on Windows 8/2012 or greater. Skipping these properties!")
else
install_command << " -Source \"#{new_resource.source}\"" if new_resource.source
install_command << ' -IncludeManagementTools' if new_resource.management_tools
end
cmd = powershell_out!(install_command, timeout: new_resource.timeout)
Chef::Log.info(cmd.stdout)
reload_cached_powershell_data # Reload cached powershell feature state
end
end
end
action :remove do
if installed?
converge_by("remove Windows feature #{new_resource.feature_name}") do
cmd = powershell_out!("#{remove_feature_cmdlet} #{to_array(new_resource.feature_name).join(',')}")
raise_on_old_powershell
reload_cached_powershell_data unless node['powershell_features_cache']
Chef::Log.debug("Windows features needing removal: #{features_to_remove.empty? ? 'none' : features_to_remove.join(',')}")
unless features_to_remove.empty?
converge_by("remove Windows feature#{'s' if features_to_remove.count > 1} #{features_to_remove.join(',')}") do
cmd = powershell_out!("#{remove_feature_cmdlet} #{features_to_remove.join(',')}", timeout: new_resource.timeout)
Chef::Log.info(cmd.stdout)
reload_cached_powershell_data # Reload cached powershell feature state
end
end
end
action :delete do
if available?
converge_by("delete Windows feature #{new_resource.feature_name} from the image") do
cmd = powershell_out!("Uninstall-WindowsFeature #{to_array(new_resource.feature_name).join(',')} -Remove")
raise_on_old_powershell
raise_if_delete_unsupported
reload_cached_powershell_data unless node['powershell_features_cache']
fail_if_unavailable # fail if the features don't exist
Chef::Log.debug("Windows features needing deletion: #{features_to_delete.empty? ? 'none' : features_to_delete.join(',')}")
unless features_to_delete.empty?
converge_by("delete Windows feature#{'s' if features_to_delete.count > 1} #{features_to_delete.join(',')} from the image") do
cmd = powershell_out!("Uninstall-WindowsFeature #{features_to_delete.join(',')} -Remove", timeout: new_resource.timeout)
Chef::Log.info(cmd.stdout)
reload_cached_powershell_data # Reload cached powershell feature state
end
end
end
action_class do
# shellout to determine the actively installed version of powershell
# we have this same data in ohai, but it doesn't get updated if powershell is installed mid run
# @return [Integer] the powershell version or 0 for nothing
def powershell_version
cmd = powershell_out('$PSVersionTable.psversion.major')
return 1 if cmd.stdout.empty? # PowerShell 1.0 doesn't have a $PSVersionTable
Regexp.last_match(1).to_i if cmd.stdout =~ /^(\d+)/
rescue Errno::ENOENT
0 # zero as in nothing is installed
end
# raise if we're running powershell less than 3.0 since we need convertto-json
# check the powershell version via ohai data and if we're < 3.0 also shellout to make sure as
# a newer version could be installed post ohai run. Yes we're double checking. It's fine.
# @todo this can go away when we fully remove support for Windows 2008 R2
# @raise [RuntimeError] Raise if powershell is < 3.0
def raise_on_old_powershell
# be super defensive about the powershell lang plugin not being there
return if node['languages'] && node['languages']['powershell'] && node['languages']['powershell']['version'].to_i >= 3
raise 'The windows_feature_powershell resource requires PowerShell 3.0 or later. Please install PowerShell 3.0+ before running this resource.' if powershell_version < 3
end
# The appropirate cmdlet to install a windows feature based on windows release
# @return [String]
def install_feature_cmdlet
node['os_version'].to_f < 6.2 ? 'Import-Module ServerManager; Add-WindowsFeature' : 'Install-WindowsFeature'
older_than_2012_or_8? ? 'Add-WindowsFeature' : 'Install-WindowsFeature'
end
# The appropirate cmdlet to remove a windows feature based on windows release
# @return [String]
def remove_feature_cmdlet
node['os_version'].to_f < 6.2 ? 'Import-Module ServerManager; Remove-WindowsFeature' : 'Uninstall-WindowsFeature'
older_than_2012_or_8? ? 'Remove-WindowsFeature' : 'Uninstall-WindowsFeature'
end
def installed?
@installed ||= begin
cmd = powershell_out("(Get-WindowsFeature #{to_array(new_resource.feature_name).join(',')} | ?{$_.InstallState -ne \'Installed\'}).count")
cmd.stderr.empty? && cmd.stdout.chomp.to_i == 0
# @return [Array] features the user has requested to install which need installation
def features_to_install
# the intersection of the features to install & disabled features are what needs installing
@install ||= new_resource.feature_name & node['powershell_features_cache']['disabled']
end
# @return [Array] features the user has requested to remove which need removing
def features_to_remove
# the intersection of the features to remove & enabled features are what needs removing
@remove ||= new_resource.feature_name & node['powershell_features_cache']['enabled']
end
# @return [Array] features the user has requested to delete which need deleting
def features_to_delete
# the intersection of the features to remove & enabled/disabled features are what needs removing
@remove ||= begin
all_available = node['powershell_features_cache']['enabled'] +
node['powershell_features_cache']['disabled']
new_resource.feature_name & all_available
end
end
def available?
@available ||= begin
cmd = powershell_out("(Get-WindowsFeature #{to_array(new_resource.feature_name).join(',')} | ?{$_.InstallState -ne \'Removed\'}).count")
cmd.stderr.empty? && cmd.stdout.chomp.to_i > 0
end
end
end
action :install do
Chef::Log.warn("Requested feature #{new_resource.feature_name} is not available on this system.") unless available?
unless !available? || installed?
converge_by("install Windows feature #{new_resource.feature_name}") do
addsource = new_resource.source ? "-Source \"#{new_resource.source}\"" : ''
addall = new_resource.all ? '-IncludeAllSubFeature' : ''
cmd = if node['os_version'].to_f < 6.2
powershell_out!("#{install_feature_cmdlet} #{to_array(new_resource.feature_name).join(',')} #{addall}")
else
powershell_out!("#{install_feature_cmdlet} #{to_array(new_resource.feature_name).join(',')} #{addsource} #{addall}")
end
Chef::Log.info(cmd.stdout)
# if any features are not supported on this release of Windows or
# have been deleted raise with a friendly message. At one point in time
# we just warned, but this goes against the behavior of ever other package
# provider in Chef and it isn't clear what you'd want if you passed an array
# and some features were available and others were not.
# @return [void]
def fail_if_unavailable
all_available = node['powershell_features_cache']['enabled'] +
node['powershell_features_cache']['disabled'] +
node['powershell_features_cache']['removed']
# the difference of desired features to install to all features is what's not available
unavailable = (new_resource.feature_name - all_available)
raise "The Windows feature#{'s' if unavailable.count > 1} #{unavailable.join(',')} #{unavailable.count > 1 ? 'are' : 'is'} not available on this version of Windows. Run 'Get-WindowsFeature' to see the list of available feature names." unless unavailable.empty?
end
# run Get-WindowsFeature to get a list of all available features and their state
# and save that to the node at node.override level.
# @return [void]
def reload_cached_powershell_data
Chef::Log.debug('Caching Windows features available via Get-WindowsFeature.')
node.override['powershell_features_cache'] = Mash.new
node.override['powershell_features_cache']['enabled'] = []
node.override['powershell_features_cache']['disabled'] = []
node.override['powershell_features_cache']['removed'] = []
parsed_feature_list.each do |feature_details_raw|
case feature_details_raw['InstallState']
when 5 # matches 'Removed' InstallState
add_to_feature_mash('removed', feature_details_raw['Name'])
when 1, 3 # matches 'Installed' or 'InstallPending' states
add_to_feature_mash('enabled', feature_details_raw['Name'])
when 0, 2 # matches 'Available' or 'UninstallPending' states
add_to_feature_mash('disabled', feature_details_raw['Name'])
end
end
Chef::Log.debug("The powershell cache contains\n#{node['powershell_features_cache']}")
end
# fetch the list of available feature names and state in JSON and parse the JSON
def parsed_feature_list
# Grab raw feature information from dism command line
# Windows < 2012 doesn't present a state value so we have to check if the feature is installed or not
raw_list_of_features = if older_than_2012_or_8? # make the older format look like the new format, warts and all
powershell_out!('Get-WindowsFeature | Select-Object -Property Name, @{Name=\"InstallState\"; Expression = {If ($_.Installed) { 1 } Else { 0 }}} | ConvertTo-Json -Compress', timeout: new_resource.timeout).stdout
else
powershell_out!('Get-WindowsFeature | Select-Object -Property Name,InstallState | ConvertTo-Json -Compress', timeout: new_resource.timeout).stdout
end
Chef::JSONCompat.from_json(raw_list_of_features)
end
# add the features values to the appropriate array
# @return [void]
def add_to_feature_mash(feature_type, feature_details)
# add the lowercase feature name to the mash unless we're on < 2012 where they're case sensitive
node.override['powershell_features_cache'][feature_type] << (older_than_2012_or_8? ? feature_details : feature_details.downcase)
end
# Fail if any of the packages are in a removed state
# @return [void]
def fail_if_removed
return if new_resource.source # if someone provides a source then all is well
if node['platform_version'].to_f > 6.2 # 2012R2 or later
return if registry_key_exists?('HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Servicing') && registry_value_exists?('HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Servicing', name: 'LocalSourcePath') # if source is defined in the registry, still fine
end
removed = new_resource.feature_name & node['powershell_features_cache']['removed']
raise "The Windows feature#{'s' if removed.count > 1} #{removed.join(',')} #{removed.count > 1 ? 'are' : 'is'} have been removed from the host and cannot be installed." unless removed.empty?
end
# Fail unless we're on windows 8+ / 2012+ where deleting a feature is supported
def raise_if_delete_unsupported
raise Chef::Exceptions::UnsupportedAction, "#{self} :delete action not supported on Windows releases before Windows 8/2012. Cannot continue!" if older_than_2012_or_8?
end
end

View File

@@ -1,76 +0,0 @@
#
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Cookbook:: windows
# Provider:: feature_servermanagercmd
#
# Copyright:: 2011-2017, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
property :feature_name, [Array, String], name_attribute: true
property :source, String
property :all, [true, false], default: false
include Chef::Mixin::ShellOut
include Windows::Helper
action :install do
unless installed?
converge_by("install Windows feature #{new_resource.feature_name}") do
check_reboot(shell_out("#{servermanagercmd} -install #{to_array(new_resource.feature_name).join(' ')}", returns: [0, 42, 127, 1003, 3010]), new_resource.feature_name)
end
end
end
action :remove do
if installed?
converge_by("removing Windows feature #{new_resource.feature_name}") do
check_reboot(shell_out("#{servermanagercmd} -remove #{to_array(new_resource.feature_name).join(' ')}", returns: [0, 42, 127, 1003, 3010]), new_resource.feature_name)
end
end
end
action :delete do
Chef::Log.warn('servermanagercmd does not support removing a feature from the image.')
end
# Exit codes are listed at http://technet.microsoft.com/en-us/library/cc749128(v=ws.10).aspx
action_class do
def check_reboot(result, feature)
if result.exitstatus == 3010 # successful, but needs reboot
node.run_state['reboot_requested'] = true
Chef::Log.warn("Require reboot to install #{feature}")
elsif result.exitstatus == 1001 # failure, but needs reboot before we can do anything else
node.run_state['reboot_requested'] = true
Chef::Log.warn("Failed installing #{feature} and need to reboot")
end
result.error! # throw for any other bad results. The above results will also get raised, and should cause a reboot via the handler.
end
def installed?
@installed ||= begin
cmd = shell_out("#{servermanagercmd} -query", returns: [0, 42, 127, 1003])
cmd.stderr.empty? && (cmd.stdout =~ /^\s*?\[X\]\s.+?\s\[#{new_resource.feature_name}\]\s*$/i)
end
end
# account for File System Redirector
# http://msdn.microsoft.com/en-us/library/aa384187(v=vs.85).aspx
def servermanagercmd
@servermanagercmd ||= begin
locate_sysnative_cmd('servermanagercmd.exe')
end
end
end

View File

@@ -3,8 +3,8 @@
# Cookbook:: windows
# Resource:: font
#
# Copyright:: 2014-2017, Schuberg Philis BV.
# Copyright:: 2017, Chef Software, Inc.
# Copyright:: 2014-2018, Schuberg Philis BV.
# Copyright:: 2017-2018, Chef Software Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -19,14 +19,17 @@
# limitations under the License.
#
property :name, String, name_property: true
property :source, String, required: false
require 'chef/util/path_helper'
include Windows::Helper
chef_version_for_provides '< 14.0' if respond_to?(:chef_version_for_provides)
resource_name :windows_font
property :font_name, String, name_property: true
property :source, String, required: false, coerce: proc { |x| x =~ /^.:.*/ ? x.tr('\\', '/').gsub('//', '/') : x }
action :install do
if font_exists?
Chef::Log.debug("Not installing font: #{new_resource.name}, font already installed.")
Chef::Log.debug("Not installing font: #{new_resource.font_name} as font already installed.")
else
retrieve_cookbook_font
install_font
@@ -35,46 +38,74 @@ action :install do
end
action_class do
# if a source is specified fetch using remote_file. If not use cookbook_file
def retrieve_cookbook_font
font_file = new_resource.name
font_file = new_resource.font_name
if new_resource.source
remote_file font_file do
action :nothing
source "file://#{new_resource.source}"
path win_friendly_path(::File.join(ENV['TEMP'], font_file))
action :nothing
source source_uri
path Chef::Util::PathHelper.join(ENV['TEMP'], font_file)
end.run_action(:create)
else
cookbook_file font_file do
action :nothing
cookbook cookbook_name.to_s unless cookbook_name.nil?
path win_friendly_path(::File.join(ENV['TEMP'], font_file))
path Chef::Util::PathHelper.join(ENV['TEMP'], font_file)
end.run_action(:create)
end
end
# delete the temp cookbook file
def del_cookbook_font
file ::File.join(ENV['TEMP'], new_resource.name) do
file Chef::Util::PathHelper.join(ENV['TEMP'], new_resource.font_name) do
action :delete
end
end
# install the font into the appropriate fonts directory
def install_font
require 'win32ole' if RUBY_PLATFORM =~ /mswin|mingw32|windows/
fonts_dir = WIN32OLE.new('WScript.Shell').SpecialFolders('Fonts')
folder = WIN32OLE.new('Shell.Application').Namespace(fonts_dir)
converge_by("install font #{new_resource.name}") do
folder.CopyHere(win_friendly_path(::File.join(ENV['TEMP'], new_resource.name)))
converge_by("install font #{new_resource.font_name} to #{fonts_dir}") do
folder.CopyHere(Chef::Util::PathHelper.join(ENV['TEMP'], new_resource.font_name))
end
end
# Check to see if the font is installed
# Check to see if the font is installed in the fonts dir
#
# === Returns
# <true>:: If the font is installed
# <false>:: If the font is not instaled
# @return [Boolean] Is the font is installed?
def font_exists?
require 'win32ole' if RUBY_PLATFORM =~ /mswin|mingw32|windows/
fonts_dir = WIN32OLE.new('WScript.Shell').SpecialFolders('Fonts')
::File.exist?(win_friendly_path(::File.join(fonts_dir, new_resource.name)))
fonts_dir = Chef::Util::PathHelper.join(ENV['windir'], 'fonts')
Chef::Log.debug("Seeing if the font at #{Chef::Util::PathHelper.join(fonts_dir, new_resource.font_name)} exists")
::File.exist?(Chef::Util::PathHelper.join(fonts_dir, new_resource.font_name))
end
# Parse out the schema provided to us to see if it's one we support via remote_file.
# We do this because URI will parse C:/foo as schema 'c', which won't work with remote_file
#
# @return [Boolean]
def remote_file_schema?(schema)
return true if %w(http https ftp).include?(schema)
end
# return new_resource.source if we have a proper URI specified
# if it's a local file listed as a source return it in file:// format
#
# @return [String] path to the font
def source_uri
begin
require 'uri'
if remote_file_schema?(URI.parse(new_resource.source).scheme)
Chef::Log.debug('source property starts with ftp/http. Using source property unmodified')
return new_resource.source
end
rescue URI::InvalidURIError
Chef::Log.warn("source property of #{new_resource.source} could not be processed as a URI. Check the format you provided.")
end
Chef::Log.debug('source property does not start with ftp/http. Prepending with file:// as it appears to be a local file.')
"file://#{new_resource.source}"
end
end

View File

@@ -18,10 +18,9 @@
# limitations under the License.
#
include Chef::Mixin::ShellOut
include Windows::Helper
property :url, String, name_property: true, required: true
property :url, String, name_property: true
property :user, String
property :sddl, String
property :exists, [true, false], desired_state: true
@@ -36,7 +35,7 @@ load_current_value do |desired|
exists true
url desired.url
# Checks first for sddl, because it generates user(s)
sddl_match = cmd_out.match(/SDDL:\s*(?<sddl>.+)/)
sddl_match = cmd_out.match(/SDDL:\s*(?<sddl>\S+)/)
if sddl_match
sddl sddl_match['sddl']
else

View File

@@ -3,8 +3,8 @@
# Cookbook:: windows
# Resource:: pagefile
#
# Copyright:: 2012-2017, Nordstrom, Inc.
# Copyright:: 2017, Chef Software, Inc.
# Copyright:: 2012-2018, Nordstrom, Inc.
# Copyright:: 2017-2018, Chef Software Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -19,17 +19,19 @@
# limitations under the License.
#
property :name, String, name_property: true
chef_version_for_provides '< 14.0' if respond_to?(:chef_version_for_provides)
resource_name :windows_pagefile
property :path, String, coerce: proc { |x| x.tr('/', '\\') }, name_property: true
property :system_managed, [true, false]
property :automatic_managed, [true, false], default: false
property :initial_size, Integer
property :maximum_size, Integer
include Chef::Mixin::ShellOut
include Windows::Helper
action :set do
pagefile = new_resource.name
pagefile = new_resource.path
initial_size = new_resource.initial_size
maximum_size = new_resource.maximum_size
system_managed = new_resource.system_managed
@@ -58,16 +60,22 @@ end
action :delete do
validate_name
pagefile = new_resource.name
delete(pagefile) if exists?(pagefile)
delete(new_resource.path) if exists?(new_resource.path)
end
action_class do
# make sure the provided name property matches the appropriate format
# we do this here and not in the property itself because if automatic_managed
# is set then this validation is not necessary / doesn't make sense at all
def validate_name
return if /^.:.*.sys/ =~ new_resource.name
raise "#{new_resource.name} does not match the format DRIVE:\\path\\file.sys for pagefiles. Example: C:\\pagefile.sys"
return if /^.:.*.sys/ =~ new_resource.path
raise "#{new_resource.path} does not match the format DRIVE:\\path\\file.sys for pagefiles. Example: C:\\pagefile.sys"
end
# See if the pagefile exists
#
# @param [String] pagefile path to the pagefile
# @return [Boolean]
def exists?(pagefile)
@exists ||= begin
Chef::Log.debug("Checking if #{pagefile} exists by runing: #{wmic} pagefileset where SettingID=\"#{get_setting_id(pagefile)}\" list /format:list")
@@ -76,6 +84,12 @@ action_class do
end
end
# is the max/min pagefile size set?
#
# @param [String] pagefile path to the pagefile
# @param [String] min the minimum size of the pagefile
# @param [String] max the minimum size of the pagefile
# @return [Boolean]
def max_and_min_set?(pagefile, min, max)
@max_and_min_set ||= begin
Chef::Log.debug("Checking if #{pagefile} min: #{min} and max #{max} are set")
@@ -84,14 +98,20 @@ action_class do
end
end
# create a pagefile
#
# @param [String] pagefile path to the pagefile
def create(pagefile)
converge_by("create pagefile #{pagefile}") do
Chef::Log.debug("Running #{wmic} pagefileset create name=\"#{win_friendly_path(pagefile)}\"")
cmd = shell_out("#{wmic} pagefileset create name=\"#{win_friendly_path(pagefile)}\"")
Chef::Log.debug("Running #{wmic} pagefileset create name=\"#{pagefile}\"")
cmd = shell_out("#{wmic} pagefileset create name=\"#{pagefile}\"")
check_for_errors(cmd.stderr)
end
end
# delete a pagefile
#
# @param [String] pagefile path to the pagefile
def delete(pagefile)
converge_by("remove pagefile #{pagefile}") do
Chef::Log.debug("Running #{wmic} pagefileset where SettingID=\"#{get_setting_id(pagefile)}\" delete")
@@ -100,6 +120,9 @@ action_class do
end
end
# see if the pagefile is automatically managed by Windows
#
# @return [Boolean]
def automatic_managed?
@automatic_managed ||= begin
Chef::Log.debug('Checking if pagefiles are automatically managed')
@@ -108,6 +131,7 @@ action_class do
end
end
# turn on automatic management of all pagefiles by Windows
def set_automatic_managed
converge_by('set pagefile to Automatic Managed') do
Chef::Log.debug("Running #{wmic} computersystem where name=\"%computername%\" set AutomaticManagedPagefile=True")
@@ -116,6 +140,7 @@ action_class do
end
end
# turn off automatic management of all pagefiles by Windows
def unset_automatic_managed
converge_by('set pagefile to User Managed') do
Chef::Log.debug("Running #{wmic} computersystem where name=\"%computername%\" set AutomaticManagedPagefile=False")
@@ -124,6 +149,11 @@ action_class do
end
end
# set a custom size for the pagefile (vs the defaults)
#
# @param [String] pagefile path to the pagefile
# @param [String] min the minimum size of the pagefile
# @param [String] max the minimum size of the pagefile
def set_custom_size(pagefile, min, max)
converge_by("set #{pagefile} to InitialSize=#{min} & MaximumSize=#{max}") do
Chef::Log.debug("Running #{wmic} pagefileset where SettingID=\"#{get_setting_id(pagefile)}\" set InitialSize=#{min},MaximumSize=#{max}")
@@ -132,7 +162,10 @@ action_class do
end
end
def set_system_managed(pagefile) # rubocop: disable Style/AccessorMethodName
# set a pagefile size to be system managed
#
# @param [String] pagefile path to the pagefile
def set_system_managed(pagefile) # rubocop: disable Naming/AccessorMethodName
converge_by("set #{pagefile} to System Managed") do
Chef::Log.debug("Running #{wmic} pagefileset where SettingID=\"#{get_setting_id(pagefile)}\" set InitialSize=0,MaximumSize=0")
cmd = shell_out("#{wmic} pagefileset where SettingID=\"#{get_setting_id(pagefile)}\" set InitialSize=0,MaximumSize=0", returns: [0])
@@ -141,11 +174,11 @@ action_class do
end
def get_setting_id(pagefile)
pagefile = win_friendly_path(pagefile)
pagefile = pagefile.split('\\')
"#{pagefile[1]} @ #{pagefile[0]}"
split_path = pagefile.split('\\')
"#{split_path[1]} @ #{split_path[0]}"
end
# raise if there's an error on stderr on a shellout
def check_for_errors(stderr)
raise stderr.chomp unless stderr.empty?
end

View File

@@ -1,54 +0,0 @@
#
# Author:: Paul Morton (<pmorton@biaprotect.com>)
# Cookbook:: windows
# Resource:: path
#
# Copyright:: 2011-2017, Business Intelligence Associates, Inc
# Copyright:: 2017, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
property :path, String, name_property: true
include Windows::Helper
action :add do
env 'path' do
action :modify
delim ::File::PATH_SEPARATOR
value new_resource.path.tr('/', '\\')
notifies :run, "ruby_block[fix ruby ENV['PATH']]", :immediately
end
# The windows Env provider does not correctly expand variables in
# the PATH environment variable. Ruby expects these to be expanded.
# This is a temporary fix for that.
#
# Follow at https://github.com/chef/chef/pull/1876
#
ruby_block "fix ruby ENV['PATH']" do
block do
ENV['PATH'] = expand_env_vars(ENV['PATH'])
end
action :nothing
end
end
action :remove do
env 'path' do
action :delete
delim ::File::PATH_SEPARATOR
value new_resource.path.tr('/', '\\')
end
end

View File

@@ -22,7 +22,10 @@
require 'resolv'
property :device_id, String, name_property: true, required: true
chef_version_for_provides '< 14.0' if respond_to?(:chef_version_for_provides)
resource_name :windows_printer
property :device_id, String, name_property: true
property :comment, String
property :default, [true, false], default: false
property :driver_name, String, required: true

View File

@@ -3,7 +3,7 @@
# Cookbook:: windows
# Resource:: printer_port
#
# Copyright:: 2012-2017, Nordstrom, Inc.
# Copyright:: 2012-2018, Nordstrom, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -22,7 +22,10 @@
require 'resolv'
property :ipv4_address, String, name_attribute: true, required: true, regex: Resolv::IPv4::Regex
chef_version_for_provides '< 14.0' if respond_to?(:chef_version_for_provides)
resource_name :windows_printer_port
property :ipv4_address, String, name_property: true, regex: Resolv::IPv4::Regex
property :port_name, String
property :port_number, Integer, default: 9100
property :port_description, String
@@ -36,15 +39,15 @@ def port_exists?(name)
port_reg_key = PORTS_REG_KEY + name
Chef::Log.debug "Checking to see if this reg key exists: '#{port_reg_key}'"
Registry.key_exists?(port_reg_key)
registry_key_exists?(port_reg_key)
end
# @todo Set @current_resource port properties from registry
load_current_value do |desired|
name desired.name
ipv4_address desired.ipv4_address
port_name desired.port_name || "IP_#{@new_resource.ipv4_address}"
exists port_exists?(desired.port_name)
# TODO: Set @current_resource port properties from registry
port_name desired.port_name || "IP_#{desired.ipv4_address}"
exists port_exists?(desired.port_name || "IP_#{desired.ipv4_address}")
end
action :create do

View File

@@ -1,10 +1,12 @@
# -*- coding: utf-8 -*-
#
# Author:: Sölvi Páll Ásgeirsson (<solvip@gmail.com>), Richard Lavey (richard.lavey@calastone.com)
# Author:: Sölvi Páll Ásgeirsson (<solvip@gmail.com>)
# Author:: Richard Lavey (richard.lavey@calastone.com)
# Author:: Tim Smith (tsmith@chef.io)
# Cookbook:: windows
# Resource:: share
#
# Copyright:: 2014-2017, Sölvi Páll Ásgeirsson.
# Copyright:: 2018, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -19,271 +21,268 @@
# limitations under the License.
#
property :share_name, String, name_property: true
property :path, String, required: true
property :description, String, default: ''
property :full_users, Array, default: []
property :change_users, Array, default: []
property :read_users, Array, default: []
chef_version_for_provides '< 14.7' if respond_to?(:chef_version_for_provides)
resource_name :windows_share
require 'chef/json_compat'
require 'chef/util/path_helper'
# Specifies a name for the SMB share. The name may be composed of any valid file name characters, but must be less than 80 characters long. The names pipe and mailslot are reserved for use by the computer.
property :share_name, String, name_property: true
# Specifies the path of the location of the folder to share. The path must be fully qualified. Relative paths or paths that contain wildcard characters are not permitted.
property :path, String
# Specifies an optional description of the SMB share. A description of the share is displayed by running the Get-SmbShare cmdlet. The description may not contain more than 256 characters.
property :description, String, default: ''
# Specifies which accounts are granted full permission to access the share. Use a comma-separated list to specify multiple accounts. An account may not be specified more than once in the FullAccess, ChangeAccess, or ReadAccess parameter lists, but may be specified once in the FullAccess, ChangeAccess, or ReadAccess parameter list and once in the NoAccess parameter list.
property :full_users, Array, default: [], coerce: proc { |u| u.sort }
# Specifies which users are granted modify permission to access the share
property :change_users, Array, default: [], coerce: proc { |u| u.sort }
# Specifies which users are granted read permission to access the share. Multiple users can be specified by supplying a comma-separated list.
property :read_users, Array, default: [], coerce: proc { |u| u.sort }
# Specifies the lifetime of the new SMB share. A temporary share does not persist beyond the next restart of the computer. By default, new SMB shares are persistent, and non-temporary.
property :temporary, [true, false], default: false
# Specifies the scope name of the share.
property :scope_name, String, default: '*'
# Specifies the continuous availability time-out for the share.
property :ca_timeout, Integer, default: 0
# Indicates that the share is continuously available.
property :continuously_available, [true, false], default: false
# Specifies the caching mode of the offline files for the SMB share.
# property :caching_mode, String, equal_to: %w(None Manual Documents Programs BranchCache)
# Specifies the maximum number of concurrently connected users that the new SMB share may accommodate. If this parameter is set to zero (0), then the number of users is unlimited.
property :concurrent_user_limit, Integer, default: 0
# Indicates that the share is encrypted.
property :encrypt_data, [true, false], default: false
# Specifies which files and folders in the SMB share are visible to users. AccessBased: SMB does not the display the files and folders for a share to a user unless that user has rights to access the files and folders. By default, access-based enumeration is disabled for new SMB shares. Unrestricted: SMB displays files and folders to a user even when the user does not have permission to access the items.
# property :folder_enumeration_mode, String, equal_to: %(AccessBased Unrestricted)
include Windows::Helper
include Chef::Mixin::PowershellOut
require 'win32ole' if RUBY_PLATFORM =~ /mswin|mingw32|windows/
load_current_value do |desired|
# this command selects individual objects because EncryptData & CachingMode have underlying
# types that get converted to their Integer values by ConvertTo-Json & we need to make sure
# those get written out as strings
share_state_cmd = "Get-SmbShare -Name '#{desired.share_name}' | Select-Object Name,Path, Description, Temporary, CATimeout, ContinuouslyAvailable, ConcurrentUserLimit, EncryptData | ConvertTo-Json"
ACCESS_FULL = 2_032_127
ACCESS_CHANGE = 1_245_631
ACCESS_READ = 1_179_817
Chef::Log.debug("Running '#{share_state_cmd}' to determine share state'")
ps_results = powershell_out(share_state_cmd)
action :create do
if different_path?
unless current_resource.path.nil? || current_resource.path.empty?
converge_by('Removing previous share') do
delete_share
end
end
converge_by("Creating share #{current_resource.share_name}") do
create_share
end
# detect a failure without raising and then set current_resource to nil
if ps_results.error?
Chef::Log.debug("Error fetching share state: #{ps_results.stderr}")
current_value_does_not_exist!
end
if different_members?(:full_users) ||
different_members?(:change_users) ||
different_members?(:read_users) ||
different_description?
converge_by("Setting permissions and description for #{new_resource.share_name}") do
set_share_permissions
Chef::Log.debug("The Get-SmbShare results were #{ps_results.stdout}")
results = Chef::JSONCompat.from_json(ps_results.stdout)
path results['Path']
description results['Description']
temporary results['Temporary']
ca_timeout results['CATimeout']
continuously_available results['ContinuouslyAvailable']
# caching_mode results['CachingMode']
concurrent_user_limit results['ConcurrentUserLimit']
encrypt_data results['EncryptData']
# folder_enumeration_mode results['FolderEnumerationMode']
perm_state_cmd = %(Get-SmbShareAccess -Name "#{desired.share_name}" | Select-Object AccountName,AccessControlType,AccessRight | ConvertTo-Json)
Chef::Log.debug("Running '#{perm_state_cmd}' to determine share permissions state'")
ps_perm_results = powershell_out(perm_state_cmd)
# we raise here instead of warning like above because we'd only get here if the above Get-SmbShare
# command was successful and that continuing would leave us with 1/2 known state
raise "Could not determine #{desired.share_name} share permissions by running '#{perm_state_cmd}'" if ps_perm_results.error?
Chef::Log.debug("The Get-SmbShareAccess results were #{ps_perm_results.stdout}")
f_users, c_users, r_users = parse_permissions(ps_perm_results.stdout)
full_users f_users
change_users c_users
read_users r_users
end
def after_created
raise 'The windows_share resource relies on PowerShell cmdlets not present in Windows releases prior to 8/2012. Cannot continue!' if node['platform_version'].to_f < 6.3
end
# given the string output of Get-SmbShareAccess parse out
# arrays of full access users, change users, and read only users
def parse_permissions(results_string)
json_results = Chef::JSONCompat.from_json(results_string)
json_results = [json_results] unless json_results.is_a?(Array) # single result is not an array
f_users = []
c_users = []
r_users = []
json_results.each do |perm|
next unless perm['AccessControlType'] == 0 # allow
case perm['AccessRight']
when 0 then f_users << stripped_account(perm['AccountName']) # 0 full control
when 1 then c_users << stripped_account(perm['AccountName']) # 1 == change
when 2 then r_users << stripped_account(perm['AccountName']) # 2 == read
end
end
[f_users, c_users, r_users]
end
# local names are returned from Get-SmbShareAccess in the full format MACHINE\\NAME
# but users of this resource would simply say NAME so we need to strip the values for comparison
def stripped_account(name)
name.slice!("#{node['hostname']}\\")
name
end
action :create do
# we do this here instead of requiring the property because :delete doesn't need path set
raise 'No path property set' unless new_resource.path
converge_if_changed do
# you can't actually change the path so you have to delete the old share first
if different_path?
Chef::Log.debug('The path has changed so we will delete and recreate share')
delete_share
create_share
elsif current_resource.nil?
# powershell cmdlet for create is different than updates
Chef::Log.debug('The current resource is nil so we will create a new share')
create_share
else
Chef::Log.debug('The current resource was not nil so we will update an existing share')
update_share
end
# creating the share does not set permissions so we need to update
update_permissions
end
end
action :delete do
if !current_resource.path.nil? && !current_resource.path.empty?
converge_by("Deleting #{current_resource.share_name}") do
if current_resource.nil?
Chef::Log.debug("#{new_resource.share_name} does not exist - nothing to do")
else
converge_by("delete #{new_resource.share_name}") do
delete_share
end
else
Chef::Log.debug("#{current_resource.share_name} does not exist - nothing to do")
end
end
load_current_value do |desired|
wmi = WIN32OLE.connect('winmgmts://')
shares = wmi.ExecQuery("SELECT * FROM Win32_Share WHERE name = '#{desired.share_name}'")
existing_share = shares.Count == 0 ? nil : shares.ItemIndex(0)
description ''
unless existing_share.nil?
path existing_share.Path
description existing_share.Description
action_class do
def different_path?
return false if current_resource.nil? # going from nil to something isn't different for our concerns
return false if current_resource.path == Chef::Util::PathHelper.cleanpath(new_resource.path)
true
end
perms = share_permissions name
unless perms.nil?
full_users perms[:full_users]
change_users perms[:change_users]
read_users perms[:read_users]
end
end
def delete_share
delete_command = "Remove-SmbShare -Name '#{new_resource.share_name}' -Force"
def share_permissions(name)
wmi = WIN32OLE.connect('winmgmts://')
shares = wmi.ExecQuery("SELECT * FROM Win32_LogicalShareSecuritySetting WHERE name = '#{name}'")
# The security descriptor is an output parameter
sd = nil
begin
shares.ItemIndex(0).GetSecurityDescriptor(sd)
sd = WIN32OLE::ARGV[0]
rescue WIN32OLERuntimeError
Chef::Log.warn('Failed to retrieve any security information about the share.')
Chef::Log.debug("Running '#{delete_command}' to remove the share")
powershell_out!(delete_command)
end
read = []
change = []
full = []
def update_share
update_command = "Set-SmbShare -Name '#{new_resource.share_name}' -Description '#{new_resource.description}' -Force"
unless sd.nil?
sd.DACL.each do |dacl|
trustee = "#{dacl.Trustee.Domain}\\#{dacl.Trustee.Name}".downcase
case dacl.AccessMask
when ACCESS_FULL
full.push(trustee)
when ACCESS_CHANGE
change.push(trustee)
when ACCESS_READ
read.push(trustee)
else
Chef::Log.warn "Unknown access mask #{dacl.AccessMask} for user #{trustee}. This will be lost if permissions are updated"
Chef::Log.debug("Running '#{update_command}' to update the share")
powershell_out!(update_command)
end
def create_share
raise "#{new_resource.path} is missing or not a directory. Shares cannot be created if the path doesn't first exist." unless ::File.directory? new_resource.path
share_cmd = "New-SmbShare -Name '#{new_resource.share_name}' -Path '#{Chef::Util::PathHelper.cleanpath(new_resource.path)}' -Description '#{new_resource.description}' -ConcurrentUserLimit #{new_resource.concurrent_user_limit} -CATimeout #{new_resource.ca_timeout} -EncryptData:#{bool_string(new_resource.encrypt_data)} -ContinuouslyAvailable:#{bool_string(new_resource.continuously_available)}"
share_cmd << " -ScopeName #{new_resource.scope_name}" unless new_resource.scope_name == '*' # passing * causes the command to fail
share_cmd << " -Temporary:#{bool_string(new_resource.temporary)}" if new_resource.temporary # only set true
Chef::Log.debug("Running '#{share_cmd}' to create the share")
powershell_out!(share_cmd)
# New-SmbShare adds the "Everyone" user with read access no matter what so we need to remove it
# before we add our permissions
revoke_user_permissions(['Everyone'])
end
# determine what users in the current state don't exist in the desired state
# users/groups will have their permissions updated with the same command that
# sets it, but removes must be performed with Revoke-SmbShareAccess
def users_to_revoke
@users_to_revoke ||= begin
# if the resource doesn't exist then nothing needs to be revoked
if current_resource.nil?
[]
else # if it exists then calculate the current to new resource diffs
(current_resource.full_users + current_resource.change_users + current_resource.read_users) - (new_resource.full_users + new_resource.change_users + new_resource.read_users)
end
end
end
{
full_users: full,
change_users: change,
read_users: read,
}
end
# update existing permissions on a share
def update_permissions
# revoke any users that had something, but now has nothing
revoke_user_permissions(users_to_revoke) unless users_to_revoke.empty?
action_class do
def description_exists?(resource)
!resource.description.nil?
end
# set permissions for each of the permission types
%w(full read change).each do |perm_type|
# set permissions for a brand new share OR
# update permissions if the current state and desired state differ
next unless permissions_need_update?(perm_type)
grant_command = "Grant-SmbShareAccess -Name '#{new_resource.share_name}' -AccountName \"#{new_resource.send("#{perm_type}_users").join('","')}\" -Force -AccessRight #{perm_type}"
def different_description?
if description_exists?(new_resource) && description_exists?(current_resource)
new_resource.description.casecmp(current_resource.description) != 0
else
description_exists?(new_resource) || description_exists?(current_resource)
Chef::Log.debug("Running '#{grant_command}' to update the share permissions")
powershell_out!(grant_command)
end
end
def different_path?
return true if current_resource.path.nil?
win_friendly_path(new_resource.path).casecmp(win_friendly_path(current_resource.path)) != 0
# determine if permissions need to be updated.
# Brand new share with no permissions defined: no
# Brand new share with permissions defined: yes
# Existing share with differing permissions: yes
#
# @param [String] type the permissions type (Full, Read, or Change)
def permissions_need_update?(type)
property_name = "#{type}_users"
# brand new share, but nothing to set
return false if current_resource.nil? && new_resource.send(property_name).empty?
# brand new share with new permissions to set
return true if current_resource.nil? && !new_resource.send(property_name).empty?
# there's a difference between the current and desired state
return true unless (new_resource.send(property_name) - current_resource.send(property_name)).empty?
# anything else
false
end
def different_members?(permission_type)
!(current_resource.send(permission_type.to_sym) - new_resource.send(permission_type.to_sym).map(&:downcase)).empty? &&
!(new_resource.send(permission_type.to_sym).map(&:downcase) - current_resource.send(permission_type.to_sym)).empty?
# revoke user permissions from a share
# @param [Array] users
def revoke_user_permissions(users)
revoke_command = "Revoke-SmbShareAccess -Name '#{new_resource.share_name}' -AccountName \"#{users.join('","')}\" -Force"
Chef::Log.debug("Running '#{revoke_command}' to revoke share permissions")
powershell_out!(revoke_command)
end
def find_share_by_name(name)
wmi = WIN32OLE.connect('winmgmts://')
shares = wmi.ExecQuery("SELECT * FROM Win32_Share WHERE name = '#{name}'")
shares.Count == 0 ? nil : shares.ItemIndex(0)
end
def delete_share
find_share_by_name(new_resource.share_name).delete
end
def create_share
raise "#{new_resource.path} is missing or not a directory" unless ::File.directory? new_resource.path
new_share_script = <<-EOH
$share = [wmiclass]"\\\\#{ENV['COMPUTERNAME']}\\root\\CimV2:Win32_Share"
$result=$share.Create('#{new_resource.path}',
'#{new_resource.share_name}',
0,
16777216,
'#{new_resource.description}',
$null,
$null)
exit $result.returnValue
EOH
r = powershell_out new_share_script
message = case r.exitstatus
when 2
'2 : Access Denied'
when 8
'8 : Unknown Failure'
when 9
'9 : Invalid Name'
when 10
'10 : Invalid Level'
when 21
'21 : Invalid Parameter'
when 22
'22 : Duplicate Share'
when 23
'23 : Redirected Path'
when 24
'24 : Unknown Device or Directory'
when 25
'25 : Net Name Not Found'
else
r.exitstatus.to_s
end
raise "Could not create share. Win32_Share.create returned #{message}" if r.error?
end
# set_share_permissions - Enforce the share permissions as dictated by the resource attributes
def set_share_permissions
share_permissions_script = <<-EOH
Function New-SecurityDescriptor
{
param (
[array]$ACEs
)
#Create SeCDesc object
$SecDesc = ([WMIClass] "\\\\$env:ComputerName\\root\\cimv2:Win32_SecurityDescriptor").CreateInstance()
foreach ($ACE in $ACEs )
{
$SecDesc.DACL += $ACE.psobject.baseobject
}
#Return the security Descriptor
return $SecDesc
}
Function New-ACE
{
param (
[string] $Name,
[string] $Domain,
[string] $Permission = "Read"
)
#Create the Trusteee Object
$Trustee = ([WMIClass] "\\\\$env:computername\\root\\cimv2:Win32_Trustee").CreateInstance()
$account = get-wmiobject Win32_Account -filter "Name like '$Name' and Domain like '$Domain'"
$accountSID = [WMI] "\\\\$env:ComputerName\\root\\cimv2:Win32_SID.SID='$($account.sid)'"
$Trustee.Domain = $Domain
$Trustee.Name = $Name
$Trustee.SID = $accountSID.BinaryRepresentation
#Create ACE (Access Control List) object.
$ACE = ([WMIClass] "\\\\$env:ComputerName\\root\\cimv2:Win32_ACE").CreateInstance()
switch ($Permission)
{
"Read" { $ACE.AccessMask = 1179817 }
"Change" { $ACE.AccessMask = 1245631 }
"Full" { $ACE.AccessMask = 2032127 }
default { throw "$Permission is not a supported permission value. Possible values are 'Read','Change','Full'" }
}
$ACE.AceFlags = 3
$ACE.AceType = 0
$ACE.Trustee = $Trustee
$ACE
}
$dacl_array = @()
EOH
new_resource.full_users.each do |user|
share_permissions_script += user_to_ace(user, 'Full')
end
new_resource.change_users.each do |user|
share_permissions_script += user_to_ace(user, 'Change')
end
new_resource.read_users.each do |user|
share_permissions_script += user_to_ace(user, 'Read')
end
share_permissions_script += <<-EOH
$dacl = New-SecurityDescriptor -Aces $dacl_array
$share = get-wmiobject win32_share -filter 'Name like "#{new_resource.share_name}"'
$return = $share.SetShareInfo($null, '#{new_resource.description}', $dacl)
exit $return.returnValue
EOH
r = powershell_out(share_permissions_script)
raise "Could not set share permissions. Win32_Share.SedtShareInfo returned #{r.exitstatus}" if r.error?
end
def user_to_ace(fully_qualified_user_name, access)
domain, user = fully_qualified_user_name.split('\\')
unless domain && user
raise "Invalid user entry #{fully_qualified_user_name}. The user names must be specified as 'DOMAIN\\user'"
end
"\n$dacl_array += new-ace -Name '#{user}' -domain '#{domain}' -permission '#{access}'"
# convert True/False into "$True" & "$False"
def bool_string(bool)
# bool ? 1 : 0
bool ? '$true' : '$false'
end
end

View File

@@ -3,7 +3,8 @@
# Cookbook:: windows
# Resource:: shortcut
#
# Copyright:: 2010-2017, VMware, Inc.
# Copyright:: 2010-2018, VMware, Inc.
# Copyright:: 2017-2018, Chef Software Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -18,7 +19,10 @@
# limitations under the License.
#
property :name, String
chef_version_for_provides '< 14.0' if respond_to?(:chef_version_for_provides)
resource_name :windows_shortcut
property :shortcut_name, String, name_property: true
property :target, String
property :arguments, String
property :description, String
@@ -28,8 +32,8 @@ property :iconlocation, String
load_current_value do |desired|
require 'win32ole' if RUBY_PLATFORM =~ /mswin|mingw32|windows/
link = WIN32OLE.new('WScript.Shell').CreateShortcut(desired.name)
name desired.name
link = WIN32OLE.new('WScript.Shell').CreateShortcut(desired.shortcut_name)
name desired.shortcut_name
target(link.TargetPath)
arguments(link.Arguments)
description(link.Description)
@@ -39,8 +43,8 @@ end
action :create do
converge_if_changed do
converge_by "creating shortcut #{new_resource.name}" do
link = WIN32OLE.new('WScript.Shell').CreateShortcut(new_resource.name)
converge_by "creating shortcut #{new_resource.shortcut_name}" do
link = WIN32OLE.new('WScript.Shell').CreateShortcut(new_resource.shortcut_name)
link.TargetPath = new_resource.target unless new_resource.target.nil?
link.Arguments = new_resource.arguments unless new_resource.arguments.nil?
link.Description = new_resource.description unless new_resource.description.nil?

View File

@@ -1,384 +0,0 @@
#
# Author:: Paul Mooring (<paul@chef.io>)
# Cookbook:: windows
# Resource:: task
#
# Copyright:: 2012-2017, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Passwords can't be loaded for existing tasks, making :modify both confusing
# and not very useful
require 'chef/mixin/shell_out'
require 'rexml/document'
include Chef::Mixin::ShellOut
include Chef::Mixin::PowershellOut
property :task_name, String, name_property: true, regex: [/\A[^\/\:\*\?\<\>\|]+\z/]
property :command, String
property :cwd, String
property :user, String, default: 'SYSTEM'
property :password, String
property :run_level, equal_to: [:highest, :limited], default: :limited
property :force, [true, false], default: false
property :interactive_enabled, [true, false], default: false
property :frequency_modifier, [Integer, String], default: 1
property :frequency, equal_to: [:minute,
:hourly,
:daily,
:weekly,
:monthly,
:once,
:on_logon,
:onstart,
:on_idle], default: :hourly
property :start_day, String
property :start_time, String
property :day, [String, Integer]
property :months, String
property :idle_time, Integer
property :exists, [true, false], desired_state: true
property :status, Symbol, desired_state: true
property :enabled, [true, false], desired_state: true
def load_task_hash(task_name)
Chef::Log.debug 'Looking for existing tasks'
# we use powershell_out here instead of powershell_out! because a failure implies that the task does not exist
task_script = <<-EOH
[Console]::OutputEncoding = [Text.UTF8Encoding]::UTF8
schtasks /Query /FO LIST /V /TN \"#{task_name}\"
EOH
output = powershell_out(task_script).stdout.force_encoding('UTF-8')
if output.empty?
task = false
else
task = {}
output.split("\n").map! { |line| line.split(':', 2).map!(&:strip) }.each do |field|
if field.is_a?(Array) && field[0].respond_to?(:to_sym)
task[field[0].gsub(/\s+/, '').to_sym] = field[1]
end
end
end
task
end
load_current_value do |desired|
pathed_task_name = desired.task_name.start_with?('\\') ? desired.task_name : "\\#{desired.task_name}"
task_hash = load_task_hash pathed_task_name
task_name pathed_task_name
if task_hash.respond_to?(:[]) && task_hash[:TaskName] == pathed_task_name
exists true
status :running if task_hash[:Status] == 'Running'
enabled task_hash[:ScheduledTaskState] == 'Enabled' ? true : false
cwd task_hash[:StartIn] unless task_hash[:StartIn] == 'N/A'
command task_hash[:TaskToRun]
user task_hash[:RunAsUser]
else
exists false
end
end
action :create do
if current_resource.exists && !(task_need_update? || new_resource.force)
Chef::Log.info "#{new_resource} task already exists - nothing to do"
else
converge_by("creating a new scheduled task #{new_resource.task_name}") do
validate_user_and_password
validate_interactive_setting
validate_create_frequency_modifier
validate_create_day
validate_create_months
validate_idle_time
options = {}
options['F'] = '' if new_resource.force || task_need_update?
options['SC'] = schedule
options['MO'] = new_resource.frequency_modifier if frequency_modifier_allowed
options['I'] = new_resource.idle_time unless new_resource.idle_time.nil?
options['SD'] = new_resource.start_day unless new_resource.start_day.nil?
options['ST'] = new_resource.start_time unless new_resource.start_time.nil?
options['TR'] = new_resource.command
options['RU'] = new_resource.user
options['RP'] = new_resource.password if use_password?
options['RL'] = 'HIGHEST' if new_resource.run_level == :highest
options['IT'] = '' if new_resource.interactive_enabled
options['D'] = new_resource.day if new_resource.day
options['M'] = new_resource.months unless new_resource.months.nil?
run_schtasks 'CREATE', options
cwd(new_resource.cwd) if new_resource.cwd
end
end
end
action :run do
if current_resource.exists
if current_resource.status == :running
Chef::Log.info "#{new_resource} task is currently running, skipping run"
else
converge_by("running scheduled task #{new_resource.task_name}") do
run_schtasks 'RUN'
new_resource.updated_by_last_action true
end
end
else
Chef::Log.debug "#{new_resource} task doesn't exists - nothing to do"
end
end
action :change do
if current_resource.exists
converge_by("changing scheduled task #{new_resource.task_name}") do
validate_user_and_password
validate_interactive_setting
options = {}
options['TR'] = new_resource.command if new_resource.command
options['RU'] = new_resource.user if new_resource.user
options['RP'] = new_resource.password if new_resource.password
options['SD'] = new_resource.start_day unless new_resource.start_day.nil?
options['ST'] = new_resource.start_time unless new_resource.start_time.nil?
options['IT'] = '' if new_resource.interactive_enabled
run_schtasks 'CHANGE', options
cwd(new_resource.cwd) if new_resource.cwd != current_resource.cwd
end
else
Chef::Log.debug "#{new_resource} task doesn't exists - nothing to do"
end
end
action :delete do
if current_resource.exists
converge_by("deleting scheduled task #{new_resource.task_name}") do
# always need to force deletion
run_schtasks 'DELETE', 'F' => ''
end
else
Chef::Log.debug "#{new_resource} task doesn't exists - nothing to do"
end
end
action :end do
if current_resource.exists
if current_resource.status != :running
Chef::Log.debug "#{new_resource} is not running - nothing to do"
else
converge_by("stopping scheduled task #{new_resource.task_name}") do
run_schtasks 'END'
end
end
else
Chef::Log.fatal "#{new_resource} task doesn't exist - nothing to do"
raise Errno::ENOENT, "#{new_resource}: task does not exist, cannot end"
end
end
action :enable do
if current_resource.exists
if current_resource.enabled
Chef::Log.debug "#{new_resource} already enabled - nothing to do"
else
converge_by("enabling scheduled task #{new_resource.task_name}") do
run_schtasks 'CHANGE', 'ENABLE' => ''
end
end
else
Chef::Log.fatal "#{new_resource} task doesn't exist - nothing to do"
raise Errno::ENOENT, "#{new_resource}: task does not exist, cannot enable"
end
end
action :disable do
if current_resource.exists
if current_resource.enabled
converge_by("disabling scheduled task #{new_resource.task_name}") do
run_schtasks 'CHANGE', 'DISABLE' => ''
end
else
Chef::Log.debug "#{new_resource} already disabled - nothing to do"
end
else
Chef::Log.debug "#{new_resource} task doesn't exist - nothing to do"
end
end
action_class do
# rubocop:disable Style/StringLiteralsInInterpolation
def run_schtasks(task_action, options = {})
cmd = "schtasks /#{task_action} /TN \"#{new_resource.task_name}\" "
options.keys.each do |option|
cmd += "/#{option} "
cmd += "\"#{options[option].to_s.gsub('"', "\\\"")}\" " unless options[option] == ''
end
Chef::Log.debug('running: ')
Chef::Log.debug(" #{cmd}")
shell_out!(cmd, returns: [0])
end
# rubocop:enable Style/StringLiteralsInInterpolation
def task_need_update?
# gsub needed as schtasks converts single quotes to double quotes on creation
current_resource.command != new_resource.command.tr("'", '"') ||
current_resource.user != new_resource.user
end
def cwd(folder)
Chef::Log.debug 'looking for existing tasks'
# we use shell_out here instead of shell_out! because a failure implies that the task does not exist
xml_cmd = shell_out("schtasks /Query /TN \"#{new_resource.task_name}\" /XML")
return if xml_cmd.exitstatus != 0
doc = REXML::Document.new(xml_cmd.stdout)
Chef::Log.debug 'Removing former CWD if any'
doc.root.elements.delete('Actions/Exec/WorkingDirectory')
unless folder.nil?
Chef::Log.debug 'Setting CWD as #folder'
cwd_element = REXML::Element.new('WorkingDirectory')
cwd_element.add_text(folder)
exec_element = doc.root.elements['Actions/Exec']
exec_element.add_element(cwd_element)
end
temp_task_file = ::File.join(ENV['TEMP'], 'windows_task.xml')
begin
::File.open(temp_task_file, 'w:UTF-16LE') do |f|
doc.write(f)
end
options = {}
options['RU'] = new_resource.user if new_resource.user
options['RP'] = new_resource.password if new_resource.password
options['IT'] = '' if new_resource.interactive_enabled
options['XML'] = temp_task_file
run_schtasks('DELETE', 'F' => '')
run_schtasks('CREATE', options)
ensure
::File.delete(temp_task_file)
end
end
SYSTEM_USERS = ['NT AUTHORITY\SYSTEM', 'SYSTEM', 'NT AUTHORITY\LOCALSERVICE', 'NT AUTHORITY\NETWORKSERVICE'].freeze
def validate_user_and_password
return unless new_resource.user && use_password?
return unless new_resource.password.nil?
Chef::Log.fatal "#{new_resource.task_name}: Can't specify a non-system user without a password!"
end
def validate_interactive_setting
return unless new_resource.interactive_enabled && new_resource.password.nil?
Chef::Log.fatal "#{new_resource} did not provide a password when attempting to set interactive/non-interactive."
end
def validate_create_day
return unless new_resource.day
unless [:weekly, :monthly].include?(new_resource.frequency)
raise 'day attribute is only valid for tasks that run weekly or monthly'
end
return unless new_resource.day.is_a?(String) && new_resource.day.to_i.to_s != new_resource.day
days = new_resource.day.split(',')
days.each do |day|
unless ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun', '*'].include?(day.strip.downcase)
raise 'day attribute invalid. Only valid values are: MON, TUE, WED, THU, FRI, SAT, SUN and *. Multiple values must be separated by a comma.'
end
end
end
def validate_create_months
return unless new_resource.months
unless [:monthly].include?(new_resource.frequency)
raise 'months attribute is only valid for tasks that run monthly'
end
return unless new_resource.months.is_a? String
months = new_resource.months.split(',')
months.each do |month|
unless ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC', '*'].include?(month.strip.upcase)
raise 'months attribute invalid. Only valid values are: JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC and *. Multiple values must be separated by a comma.'
end
end
end
def validate_idle_time
return unless new_resource.frequency == :on_idle
return if new_resource.idle_time.to_i > 0 && new_resource.idle_time.to_i <= 999
raise "idle_time value #{new_resource.idle_time} is invalid. Valid values for :on_idle frequency are 1 - 999."
end
def validate_create_frequency_modifier
# Currently is handled in create action 'frequency_modifier_allowed' line. Does not allow for frequency_modifier for once,onstart,onlogon,onidle
# Note that 'OnEvent' is not a supported frequency.
return if new_resource.frequency.nil? || new_resource.frequency_modifier.nil?
case new_resource.frequency
when :minute
unless new_resource.frequency_modifier.to_i > 0 && new_resource.frequency_modifier.to_i <= 1439
raise "frequency_modifier value #{new_resource.frequency_modifier} is invalid. Valid values for :minute frequency are 1 - 1439."
end
when :hourly
unless new_resource.frequency_modifier.to_i > 0 && new_resource.frequency_modifier.to_i <= 23
raise "frequency_modifier value #{new_resource.frequency_modifier} is invalid. Valid values for :hourly frequency are 1 - 23."
end
when :daily
unless new_resource.frequency_modifier.to_i > 0 && new_resource.frequency_modifier.to_i <= 365
raise "frequency_modifier value #{new_resource.frequency_modifier} is invalid. Valid values for :daily frequency are 1 - 365."
end
when :weekly
unless new_resource.frequency_modifier.to_i > 0 && new_resource.frequency_modifier.to_i <= 52
raise "frequency_modifier value #{new_resource.frequency_modifier} is invalid. Valid values for :weekly frequency are 1 - 52."
end
when :monthly
unless ('1'..'12').to_a.push('FIRST', 'SECOND', 'THIRD', 'FOURTH', 'LAST', 'LASTDAY').include?(new_resource.frequency_modifier.to_s.upcase)
raise "frequency_modifier value #{new_resource.frequency_modifier} is invalid. Valid values for :monthly frequency are 1 - 12, 'FIRST', 'SECOND', 'THIRD', 'FOURTH', 'LAST', 'LASTDAY'."
end
end
end
def use_password?
@use_password ||= !SYSTEM_USERS.include?(new_resource.user.upcase)
end
def schedule
case new_resource.frequency
when :on_logon
'ONLOGON'
when :on_idle
'ONIDLE'
else
new_resource.frequency
end
end
def frequency_modifier_allowed
case new_resource.frequency
when :minute, :hourly, :daily, :weekly
true
when :monthly
new_resource.months.nil? || %w(FIRST SECOND THIRD FOURTH LAST LASTDAY).include?(new_resource.frequency_modifier)
else
false
end
end
end

View File

@@ -0,0 +1,40 @@
#
# Author:: Jared Kauppila (<jared@kauppi.la>)
# Cookbook:: windows
# Resource:: user_privilege
#
property :principal, String, name_property: true
property :privilege, [Array, String], required: true, coerce: proc { |v| [*v].sort }
action :add do
([*new_resource.privilege] - [*current_resource.privilege]).each do |user_right|
converge_by("adding user privilege #{user_right}") do
Chef::ReservedNames::Win32::Security.add_account_right(new_resource.principal, user_right)
end
end
end
action :remove do
if Gem::Version.new(Chef::VERSION) < Gem::Version.new('14.4.10')
Chef::Log.warn('Chef 14.4.10 is required to use windows_privilege remove action')
else
curr_res_privilege = current_resource.privilege
new_res_privilege = new_resource.privilege
missing_res_privileges = (new_res_privilege - curr_res_privilege)
if missing_res_privileges
Chef::Log.info("Privilege: #{missing_res_privileges.join(', ')} not present. Unable to delete")
end
(new_res_privilege - missing_res_privileges).each do |user_right|
converge_by("removing user privilege #{user_right}") do
Chef::ReservedNames::Win32::Security.remove_account_right(new_resource.principal, user_right)
end
end
end
end
load_current_value do |desired|
privilege Chef::ReservedNames::Win32::Security.get_account_right(desired.principal)
end

View File

@@ -1,11 +1,12 @@
#
# Author:: Doug MacEachern (<dougm@vmware.com>)
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Author:: Wade Peacock (<wade.peacock@visioncritical.com>)
# Cookbook:: windows
# Resource:: zipfile
#
# Copyright:: 2010-2017, VMware, Inc.
# Copyright:: 2011-2017, Chef Software, Inc.
# Copyright:: 2011-2018, Chef Software, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -20,20 +21,19 @@
# limitations under the License.
#
require 'chef/util/path_helper'
property :path, String, name_property: true
property :source, String
property :overwrite, [true, false], default: false
property :checksum, String
include Windows::Helper
require 'find'
action :unzip do
ensure_rubyzip_gem_installed
Chef::Log.debug("unzip #{new_resource.source} => #{new_resource.path} (overwrite=#{new_resource.overwrite})")
cache_file_path = if new_resource.source =~ %r{^(file|ftp|http|https):\/\/} # http://rubular.com/r/DGoIWjLfGI
uri = as_uri(source)
uri = as_uri(new_resource.source)
local_cache_path = "#{Chef::Config[:file_cache_path]}/#{::File.basename(::URI.unescape(uri.path))}"
Chef::Log.debug("Caching a copy of file #{new_resource.source} at #{cache_file_path}")
@@ -48,7 +48,7 @@ action :unzip do
new_resource.source
end
cache_file_path = win_friendly_path(cache_file_path)
cache_file_path = Chef::Util::PathHelper.cleanpath(cache_file_path)
converge_by("unzip #{new_resource.source}") do
ruby_block 'Unzipping' do
@@ -111,12 +111,14 @@ action :zip do
end
action_class do
include Windows::Helper
require 'find'
def ensure_rubyzip_gem_installed
require 'zip'
rescue LoadError
Chef::Log.info("Missing gem 'rubyzip'...installing now.")
chef_gem 'rubyzip' do
version node['windows']['rubyzipversion']
action :install
compile_time true
end