Update the mediawiki cookbook and upstream cookbooks
Compatibility with Chef 14
This commit is contained in:
@@ -1,2 +0,0 @@
|
||||
~FC059
|
||||
~FC016
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 } },
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
11
cookbooks/windows/metadata.rb
Normal file
11
cookbooks/windows/metadata.rb
Normal 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'
|
||||
153
cookbooks/windows/providers/dns.rb
Normal file
153
cookbooks/windows/providers/dns.rb
Normal 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
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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?
|
||||
|
||||
@@ -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
|
||||
40
cookbooks/windows/resources/user_privilege.rb
Normal file
40
cookbooks/windows/resources/user_privilege.rb
Normal 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
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user