specinfra 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,24 @@
1
+ module SpecInfra
2
+ module Command
3
+ class Debian < Linux
4
+ def check_enabled(service, level=3)
5
+ # Until everything uses Upstart, this needs an OR.
6
+ "ls /etc/rc#{level}.d/ | grep -- #{escape(service)} || grep 'start on' /etc/init/#{escape(service)}.conf"
7
+ end
8
+
9
+ def check_installed(package, version=nil)
10
+ escaped_package = escape(package)
11
+ cmd = "dpkg -s #{escaped_package} && ! dpkg -s #{escaped_package} | grep -E '^Status: .+ not-installed$'"
12
+ if version
13
+ cmd = "#{cmd} && dpkg -s #{escaped_package} | grep -E '^Version: #{escape(version)}$'"
14
+ end
15
+ cmd
16
+ end
17
+
18
+ def check_running(service)
19
+ # This is compatible with Debian >Jaunty and Ubuntu derivatives
20
+ "service #{escape(service)} status | grep 'running'"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,23 @@
1
+ module SpecInfra
2
+ module Command
3
+ class FreeBSD < Base
4
+ def check_enabled(service, level=3)
5
+ "service -e | grep -- #{escape(service)}"
6
+ end
7
+
8
+ def check_installed(package, version=nil)
9
+ "pkg_info -Ix #{escape(package)}"
10
+ end
11
+
12
+ def check_listening(port)
13
+ regexp = ":#{port} "
14
+ "sockstat -46l -p #{port} | grep -- #{escape(regexp)}"
15
+ end
16
+
17
+ def check_mode(file, mode)
18
+ regexp = "^#{mode}$"
19
+ "stat -f%Lp #{escape(file)} | grep -- #{escape(regexp)}"
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,18 @@
1
+ module SpecInfra
2
+ module Command
3
+ class Gentoo < Linux
4
+ def check_enabled(service, level=3)
5
+ regexp = "^\\s*#{service}\\s*|\\s*\\(boot\\|default\\)"
6
+ "rc-update show | grep -- #{escape(regexp)}"
7
+ end
8
+
9
+ def check_installed(package, version=nil)
10
+ "eix #{escape(package)} --installed"
11
+ end
12
+
13
+ def check_running(service)
14
+ "/etc/init.d/#{escape(service)} status"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,68 @@
1
+ module SpecInfra
2
+ module Command
3
+ class Linux < Base
4
+ def check_access_by_user(file, user, access)
5
+ "su -s /bin/sh -c \"test -#{access} #{file}\" #{user}"
6
+ end
7
+
8
+ def check_iptables_rule(rule, table=nil, chain=nil)
9
+ cmd = "iptables"
10
+ cmd += " -t #{escape(table)}" if table
11
+ cmd += " -S"
12
+ cmd += " #{escape(chain)}" if chain
13
+ cmd += " | grep -- #{escape(rule)}"
14
+ cmd
15
+ end
16
+
17
+ def check_selinux(mode)
18
+ cmd = ""
19
+ cmd += "test ! -f /etc/selinux/config || (" if mode == "disabled"
20
+ cmd += "getenforce | grep -i -- #{escape(mode)} "
21
+ cmd += "&& grep -i -- ^SELINUX=#{escape(mode)}$ /etc/selinux/config"
22
+ cmd += ")" if mode == "disabled"
23
+ cmd
24
+ end
25
+
26
+ def check_kernel_module_loaded(name)
27
+ "lsmod | grep ^#{name}"
28
+ end
29
+
30
+ def get_interface_speed_of(name)
31
+ "ethtool #{name} | grep Speed | gawk '{print gensub(/Speed: ([0-9]+)Mb\\\/s/,\"\\\\1\",\"\")}'"
32
+ end
33
+
34
+ def check_ipv4_address(interface, ip_address)
35
+ ip_address = ip_address.dup
36
+ if ip_address =~ /\/\d+$/
37
+ ip_address << " "
38
+ else
39
+ ip_address << "/"
40
+ end
41
+ ip_address.gsub!(".", "\\.")
42
+ "ip addr show #{interface} | grep 'inet #{ip_address}'"
43
+ end
44
+
45
+ def check_zfs(zfs, property=nil)
46
+ if property.nil?
47
+ "zfs list -H #{escape(zfs)}"
48
+ else
49
+ commands = []
50
+ property.sort.each do |key, value|
51
+ regexp = "^#{value}$"
52
+ commands << "zfs list -H -o #{escape(key)} #{escape(zfs)} | grep -- #{escape(regexp)}"
53
+ end
54
+ commands.join(' && ')
55
+ end
56
+ end
57
+
58
+ def check_container(container)
59
+ "lxc-ls -1 | grep -w #{escape(container)}"
60
+ end
61
+
62
+ def check_container_running(container)
63
+ "lxc-info -n #{escape(container)} -t RUNNING"
64
+ end
65
+
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,21 @@
1
+ module SpecInfra
2
+ module Command
3
+ class Plamo < Linux
4
+
5
+ def check_enabled(service, level=3)
6
+ # This check is not necessarily detected whether service is enabled or not
7
+ # TODO: check rc.inet2 $SERV variable
8
+ "test -x /etc/rc.d/init.d/#{escape(service)}"
9
+ end
10
+
11
+ def check_installed(package, version=nil)
12
+ cmd = "ls /var/log/packages/#{escape(package)}"
13
+ if version
14
+ cmd = "#{cmd} && grep -E \"PACKAGE NAME:.+#{escape(package)}-#{escape(version)}\" /var/log/packages/#{escape(package)}"
15
+ end
16
+ cmd
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,37 @@
1
+ module SpecInfra
2
+ module Command
3
+ class RedHat < Linux
4
+ def check_access_by_user(file, user, access)
5
+ # Redhat-specific
6
+ "runuser -s /bin/sh -c \"test -#{access} #{file}\" #{user}"
7
+ end
8
+
9
+ def check_enabled(service, level=3)
10
+ "chkconfig --list #{escape(service)} | grep #{level}:on"
11
+ end
12
+
13
+ def check_yumrepo(repository)
14
+ "yum repolist all -C | grep ^#{escape(repository)}"
15
+ end
16
+
17
+ def check_yumrepo_enabled(repository)
18
+ "yum repolist all -C | grep ^#{escape(repository)} | grep enabled"
19
+ end
20
+
21
+ def check_installed(package,version=nil)
22
+ cmd = "rpm -q #{escape(package)}"
23
+ if version
24
+ cmd = "#{cmd} | grep -w -- #{escape(version)}"
25
+ end
26
+ cmd
27
+ end
28
+
29
+ alias :check_installed_by_rpm :check_installed
30
+
31
+ def install(package)
32
+ cmd = "yum -y install #{package}"
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,21 @@
1
+ module SpecInfra
2
+ module Command
3
+ class SmartOS < Solaris
4
+ def check_installed(package, version=nil)
5
+ cmd = "/opt/local/bin/pkgin list 2> /dev/null | grep -qw ^#{escape(package)}"
6
+ if version
7
+ cmd = "#{cmd}-#{escape(version)}"
8
+ end
9
+ cmd
10
+ end
11
+
12
+ def check_enabled(service, level=3)
13
+ "svcs -l #{escape(service)} 2> /dev/null | grep -wx '^enabled.*true$'"
14
+ end
15
+
16
+ def check_running(service)
17
+ "svcs -l #{escape(service)} status 2> /dev/null |grep -wx '^state.*online$'"
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,117 @@
1
+ module SpecInfra
2
+ module Command
3
+ class Solaris < Base
4
+ def check_enabled(service, level=3)
5
+ "svcs -l #{escape(service)} 2> /dev/null | egrep '^enabled *true$'"
6
+ end
7
+
8
+ def check_installed(package, version=nil)
9
+ cmd = "pkg list -H #{escape(package)} 2> /dev/null"
10
+ if version
11
+ cmd = "#{cmd} | grep -qw -- #{escape(version)}"
12
+ end
13
+ cmd
14
+ end
15
+
16
+ def check_listening(port)
17
+ regexp = "\\.#{port} "
18
+ "netstat -an 2> /dev/null | grep -- LISTEN | grep -- #{escape(regexp)}"
19
+ end
20
+
21
+ def check_listening_with_protocol(port, protocol)
22
+ regexp = ".*\\.#{port} "
23
+ "netstat -an -P #{escape(protocol)} 2> /dev/null | grep -- LISTEN | grep -- #{escape(regexp)}"
24
+ end
25
+
26
+ def check_running(service)
27
+ "svcs -l #{escape(service)} status 2> /dev/null | egrep '^state *online$'"
28
+ end
29
+
30
+ def check_cron_entry(user, entry)
31
+ entry_escaped = entry.gsub(/\*/, '\\*')
32
+ if user.nil?
33
+ "crontab -l | grep -- #{escape(entry_escaped)}"
34
+ else
35
+ "crontab -l #{escape(user)} | grep -- #{escape(entry_escaped)}"
36
+ end
37
+ end
38
+
39
+ def check_zfs(zfs, property=nil)
40
+ if property.nil?
41
+ "zfs list -H #{escape(zfs)}"
42
+ else
43
+ commands = []
44
+ property.sort.each do |key, value|
45
+ regexp = "^#{value}$"
46
+ commands << "zfs list -H -o #{escape(key)} #{escape(zfs)} | grep -- #{escape(regexp)}"
47
+ end
48
+ commands.join(' && ')
49
+ end
50
+ end
51
+
52
+ def check_ipfilter_rule(rule)
53
+ "ipfstat -io 2> /dev/null | grep -- #{escape(rule)}"
54
+ end
55
+
56
+ def check_ipnat_rule(rule)
57
+ regexp = "^#{rule}$"
58
+ "ipnat -l 2> /dev/null | grep -- #{escape(regexp)}"
59
+ end
60
+
61
+ def check_svcprop(svc, property, value)
62
+ regexp = "^#{value}$"
63
+ "svcprop -p #{escape(property)} #{escape(svc)} | grep -- #{escape(regexp)}"
64
+ end
65
+
66
+ def check_svcprops(svc, property)
67
+ commands = []
68
+ property.sort.each do |key, value|
69
+ regexp = "^#{value}$"
70
+ commands << "svcprop -p #{escape(key)} #{escape(svc)} | grep -- #{escape(regexp)}"
71
+ end
72
+ commands.join(' && ')
73
+ end
74
+
75
+ def check_file_contain_within(file, expected_pattern, from=nil, to=nil)
76
+ from ||= '1'
77
+ to ||= '$'
78
+ sed = "sed -n #{escape(from)},#{escape(to)}p #{escape(file)}"
79
+ checker_with_regexp = check_file_contain_with_regexp("/dev/stdin", expected_pattern)
80
+ checker_with_fixed = check_file_contain_with_fixed_strings("/dev/stdin", expected_pattern)
81
+ "#{sed} | #{checker_with_regexp} || #{sed} | #{checker_with_fixed}"
82
+ end
83
+
84
+ def check_belonging_group(user, group)
85
+ "id -Gn #{escape(user)} | grep -- #{escape(group)}"
86
+ end
87
+
88
+ def check_gid(group, gid)
89
+ regexp = "^#{group}:"
90
+ "getent group | grep -- #{escape(regexp)} | cut -f 3 -d ':' | grep -w -- #{escape(gid)}"
91
+ end
92
+
93
+ def check_home_directory(user, path_to_home)
94
+ "getent passwd #{escape(user)} | cut -f 6 -d ':' | grep -w -- #{escape(path_to_home)}"
95
+ end
96
+
97
+ def check_login_shell(user, path_to_shell)
98
+ "getent passwd #{escape(user)} | cut -f 7 -d ':' | grep -w -- #{escape(path_to_shell)}"
99
+ end
100
+
101
+ def check_access_by_user(file, user, access)
102
+ # http://docs.oracle.com/cd/E23823_01/html/816-5166/su-1m.html
103
+ ## No need for login shell as it seems that behavior as superuser is favorable for us, but needs
104
+ ## to be better tested under real solaris env
105
+ "su #{user} -c \"test -#{access} #{file}\""
106
+ end
107
+
108
+ def check_reachable(host, port, proto, timeout)
109
+ if port.nil?
110
+ "ping -n #{escape(host)} #{escape(timeout)}"
111
+ else
112
+ "nc -vvvvz#{escape(proto[0].chr)} -w #{escape(timeout)} #{escape(host)} #{escape(port)}"
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,78 @@
1
+ module SpecInfra
2
+ module Command
3
+ class Solaris10 < Solaris
4
+ # Please implement Solaris 10 specific commands
5
+
6
+ # reference: http://perldoc.perl.org/functions/stat.html
7
+ def check_mode(file, mode)
8
+ regexp = "^#{mode}$"
9
+ "perl -e 'printf \"%o\", (stat shift)[2]&07777' #{escape(file)} | grep -- #{escape(regexp)}"
10
+ end
11
+
12
+ # reference: http://perldoc.perl.org/functions/stat.html
13
+ # http://www.tutorialspoint.com/perl/perl_getpwuid.htm
14
+ def check_owner(file, owner)
15
+ regexp = "^#{owner}$"
16
+ "perl -e 'printf \"%s\", getpwuid((stat(\"#{escape(file)}\"))[4])' | grep -- #{escape(regexp)}"
17
+ end
18
+
19
+ def check_group(group)
20
+ "getent group | grep -w -- #{escape(group)}"
21
+ end
22
+
23
+ # reference: http://perldoc.perl.org/functions/stat.html
24
+ # http://www.tutorialspoint.com/perl/perl_getgrgid.htm
25
+ def check_grouped(file, group)
26
+ regexp = "^#{group}$"
27
+ "perl -e 'printf \"%s\", getgrgid((stat(\"#{escape(file)}\"))[5])' | grep -- #{escape(regexp)}"
28
+ end
29
+
30
+ # reference: http://www.tutorialspoint.com/perl/perl_readlink.htm
31
+ def check_link(link, target)
32
+ regexp = "^#{target}$"
33
+ "perl -e 'printf \"%s\", readlink(\"#{escape(link)}\")' | grep -- #{escape(regexp)}"
34
+ end
35
+
36
+ # reference: http://perldoc.perl.org/functions/stat.html
37
+ def get_mode(file)
38
+ "perl -e 'printf \"%o\", (stat shift)[2]&07777' #{escape(file)}"
39
+ end
40
+
41
+ def check_file_contain(file, expected_pattern)
42
+ "grep -- #{escape(expected_pattern)} #{escape(file)}"
43
+ end
44
+
45
+ def check_reachable(host, port, proto, timeout)
46
+ if port.nil?
47
+ "ping -n #{escape(host)} #{escape(timeout)}"
48
+ elsif proto == 'tcp'
49
+ "echo 'quit' | mconnect -p #{escape(port)} #{escape(host)} > /dev/null 2>&1"
50
+ else
51
+ raise NotImplementedError.new
52
+ end
53
+ end
54
+
55
+ def check_installed(package, version=nil)
56
+ cmd = "pkginfo -q #{escape(package)}"
57
+ if version
58
+ cmd = "#{cmd} | grep -- #{escape(version)}"
59
+ end
60
+ cmd
61
+ end
62
+
63
+ def check_file_md5checksum(file, expected)
64
+ "digest -a md5 -v #{escape(file)} | grep -iw -- #{escape(expected)}"
65
+ end
66
+
67
+ def check_belonging_group(user, group)
68
+ "id -ap #{escape(user)} | grep -- #{escape(group)}"
69
+ end
70
+
71
+ def check_authorized_key(user, key)
72
+ key.sub!(/\s+\S*$/, '') if key.match(/^\S+\s+\S+\s+\S*$/)
73
+ "grep -- #{escape(key)} ~#{escape(user)}/.ssh/authorized_keys"
74
+ end
75
+
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,7 @@
1
+ module SpecInfra
2
+ module Command
3
+ class Solaris11 < Solaris
4
+ # Please implement Solaris 11 specific commands
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,213 @@
1
+ module SpecInfra
2
+ module Command
3
+ class Windows
4
+ class NotSupportedError < Exception; end
5
+ REGISTRY_KEY_TYPES = {
6
+ :type_string => 'String',
7
+ :type_binary => 'Binary',
8
+ :type_dword => 'DWord',
9
+ :type_qword => 'QWord',
10
+ :type_multistring => 'MultiString',
11
+ :type_expandstring => 'ExpandString'
12
+ }
13
+
14
+ def method_missing method, *args
15
+ raise NotSupportedError.new "#{method} currently not supported in Windows os" if method.to_s =~ /^check_.+/
16
+ super(method, *args)
17
+ end
18
+
19
+ def check_file(file)
20
+ cmd = item_has_attribute file, 'Archive'
21
+ Backend::PowerShell::Command.new do
22
+ exec cmd
23
+ end
24
+ end
25
+
26
+ def check_file_hidden(file)
27
+ cmd = item_has_attribute file, 'Hidden'
28
+ Backend::PowerShell::Command.new do
29
+ exec cmd
30
+ end
31
+ end
32
+
33
+ def check_file_readonly(file)
34
+ cmd = item_has_attribute file, 'ReadOnly'
35
+ Backend::PowerShell::Command.new do
36
+ exec cmd
37
+ end
38
+ end
39
+
40
+ def check_file_system(file)
41
+ cmd = item_has_attribute file, 'System'
42
+ Backend::PowerShell::Command.new do
43
+ exec cmd
44
+ end
45
+ end
46
+
47
+ def check_directory(dir)
48
+ cmd = item_has_attribute dir, 'Directory'
49
+ Backend::PowerShell::Command.new do
50
+ exec cmd
51
+ end
52
+ end
53
+
54
+ def check_file_contain(file, pattern)
55
+ Backend::PowerShell::Command.new do
56
+ exec "[Io.File]::ReadAllText('#{file}') -match '#{convert_regexp(pattern)}'"
57
+ end
58
+ end
59
+
60
+ def check_file_contain_within file, pattern, from=nil, to=nil
61
+ from ||= '^'
62
+ to ||= '$'
63
+ Backend::PowerShell::Command.new do
64
+ using 'crop_text.ps1'
65
+ exec %Q[(CropText -text ([Io.File]::ReadAllText('#{file}')) -fromPattern '#{convert_regexp(from)}' -toPattern '#{convert_regexp(to)}') -match '#{pattern}']
66
+ end
67
+ end
68
+
69
+ def check_access_by_user(file, user, access)
70
+ case access
71
+ when 'r'
72
+ check_readable(file, user)
73
+ when 'w'
74
+ check_writable(file, user)
75
+ when 'x'
76
+ check_executable(file, user)
77
+ end
78
+ end
79
+
80
+ def check_readable(file, by_whom)
81
+ Backend::PowerShell::Command.new do
82
+ using 'check_file_access_rules.ps1'
83
+ exec "CheckFileAccessRules -path '#{file}' -identity '#{get_identity by_whom}' -rules @('FullControl', 'Modify', 'ReadAndExecute', 'Read', 'ListDirectory')"
84
+ end
85
+ end
86
+
87
+ def check_writable(file, by_whom)
88
+ Backend::PowerShell::Command.new do
89
+ using 'check_file_access_rules.ps1'
90
+ exec "CheckFileAccessRules -path '#{file}' -identity '#{get_identity by_whom}' -rules @('FullControl', 'Modify', 'Write')"
91
+ end
92
+ end
93
+
94
+ def check_executable(file, by_whom)
95
+ Backend::PowerShell::Command.new do
96
+ using 'check_file_access_rules.ps1'
97
+ exec "CheckFileAccessRules -path '#{file}' -identity '#{get_identity by_whom}' -rules @('FullControl', 'Modify', 'ReadAndExecute', 'ExecuteFile')"
98
+ end
99
+ end
100
+
101
+ def check_installed(package, version=nil)
102
+ version_selection = version.nil? ? "" : "-appVersion '#{version}'"
103
+ Backend::PowerShell::Command.new do
104
+ using 'find_installed_application.ps1'
105
+ exec "(FindInstalledApplication -appName '#{package}' #{version_selection}) -ne $null"
106
+ end
107
+ end
108
+
109
+ def check_enabled(service, level=nil)
110
+ Backend::PowerShell::Command.new do
111
+ using 'find_service.ps1'
112
+ exec "(FindService -name '#{service}').StartMode -eq 'Auto'"
113
+ end
114
+ end
115
+
116
+ def check_running(service)
117
+ Backend::PowerShell::Command.new do
118
+ using 'find_service.ps1'
119
+ exec "(FindService -name '#{service}').State -eq 'Running'"
120
+ end
121
+ end
122
+
123
+ def check_process(process)
124
+ Backend::PowerShell::Command.new do
125
+ exec "(Get-Process '#{process}') -ne $null"
126
+ end
127
+ end
128
+
129
+ def check_listening(port)
130
+ Backend::PowerShell::Command.new do
131
+ using 'is_port_listening.ps1'
132
+ exec "IsPortListening -portNumber #{port}"
133
+ end
134
+ end
135
+
136
+ def check_listening_with_protocol(port, protocol)
137
+ Backend::PowerShell::Command.new do
138
+ using 'is_port_listening.ps1'
139
+ exec "IsPortListening -portNumber #{port} -protocol '#{protocol}'"
140
+ end
141
+ end
142
+
143
+ def check_user(user)
144
+ user_id, domain = windows_account user
145
+ Backend::PowerShell::Command.new do
146
+ using 'find_user.ps1'
147
+ exec "(FindUser -userName '#{user_id}'#{domain.nil? ? "" : " -domain '#{domain}'"}) -ne $null"
148
+ end
149
+ end
150
+
151
+ def check_group(group)
152
+ group_id, domain = windows_account group
153
+ Backend::PowerShell::Command.new do
154
+ using 'find_group.ps1'
155
+ exec "(FindGroup -groupName '#{group_id}'#{domain.nil? ? "" : " -domain '#{domain}'"}) -ne $null"
156
+ end
157
+ end
158
+
159
+ def check_belonging_group(user, group)
160
+ user_id, user_domain = windows_account user
161
+ group_id, group_domain = windows_account group
162
+ Backend::PowerShell::Command.new do
163
+ using 'find_user.ps1'
164
+ using 'find_group.ps1'
165
+ using 'find_usergroup.ps1'
166
+ exec "(FindUserGroup -userName '#{user_id}'#{user_domain.nil? ? "" : " -userDomain '#{user_domain}'"} -groupName '#{group_id}'#{group_domain.nil? ? "" : " -groupDomain '#{group_domain}'"}) -ne $null"
167
+ end
168
+ end
169
+
170
+ def check_registry_key(key_name, key_property = {})
171
+ if key_property.empty?
172
+ cmd = "(Get-Item 'Registry::#{key_name}') -ne $null"
173
+ else
174
+ if key_property.key? :value
175
+ value = convert_key_property_value key_property
176
+ cmd = "(Compare-Object (Get-Item 'Registry::#{key_name}').GetValue('#{key_property[:name]}') #{value}) -eq $null"
177
+ else
178
+ cmd = "(Get-Item 'Registry::#{key_name}').GetValueKind('#{key_property[:name]}') -eq '#{REGISTRY_KEY_TYPES[key_property[:type]]}'"
179
+ end
180
+ end
181
+ Backend::PowerShell::Command.new { exec cmd }
182
+ end
183
+
184
+ private
185
+
186
+ def item_has_attribute item, attribute
187
+ "((Get-Item -Path '#{item}' -Force).attributes.ToString() -Split ', ') -contains '#{attribute}'"
188
+ end
189
+
190
+ def convert_key_property_value property
191
+ case property[:type]
192
+ when :type_binary
193
+ byte_array = [property[:value]].pack('H*').bytes.to_a
194
+ "([byte[]] #{byte_array.join(',')})"
195
+ when :type_dword
196
+ [property[:value].scan(/[0-9a-f]{2}/i).reverse.join].pack("H*").unpack("l").first
197
+ when :type_qword
198
+ property[:value].hex
199
+ else
200
+ string_array = property[:value].split("\n").map {|s| "'#{s}'"}.reduce {|acc, s| "#{acc},#{s}"}
201
+ "@(#{string_array})"
202
+ end
203
+ end
204
+
205
+ def windows_account account
206
+ match = /((.+)\\)?(.+)/.match account
207
+ domain = match[2]
208
+ name = match[3]
209
+ [name, domain]
210
+ end
211
+ end
212
+ end
213
+ end