Linux server.edchosting.com 4.18.0-553.79.1.lve.el7h.x86_64 #1 SMP Wed Oct 15 16:34:46 UTC 2025 x86_64
LiteSpeed
Server IP : 75.98.162.185 & Your IP : 216.73.216.163
Domains :
Cant Read [ /etc/named.conf ]
User : goons4good
Terminal
Auto Root
Create File
Create Folder
Localroot Suggester
Backdoor Destroyer
Readme
/
lib /
python3.6 /
site-packages /
salt /
modules /
Delete
Unzip
Name
Size
Permission
Date
Action
__pycache__
[ DIR ]
drwxr-xr-x
2022-10-11 05:09
inspectlib
[ DIR ]
drwxr-xr-x
2022-10-11 05:09
__init__.py
35
B
-rw-r--r--
2022-05-16 09:16
acme.py
12.74
KB
-rw-r--r--
2022-05-16 09:16
aix_group.py
4.11
KB
-rw-r--r--
2022-05-16 09:16
aix_shadow.py
1.93
KB
-rw-r--r--
2022-05-16 09:16
aixpkg.py
10.91
KB
-rw-r--r--
2022-05-16 09:16
aliases.py
5.07
KB
-rw-r--r--
2022-05-16 09:16
alternatives.py
5.1
KB
-rw-r--r--
2022-05-16 09:16
ansiblegate.py
11.38
KB
-rw-r--r--
2022-05-16 09:16
apache.py
12.47
KB
-rw-r--r--
2022-05-16 09:16
apcups.py
2.21
KB
-rw-r--r--
2022-05-16 09:16
apf.py
3.09
KB
-rw-r--r--
2022-05-16 09:16
apkpkg.py
16
KB
-rw-r--r--
2022-05-16 09:16
aptly.py
15.28
KB
-rw-r--r--
2022-05-16 09:16
aptpkg.py
102.35
KB
-rw-r--r--
2022-05-16 09:16
archive.py
46.97
KB
-rw-r--r--
2022-05-16 09:16
arista_pyeapi.py
22.06
KB
-rw-r--r--
2022-05-16 09:16
artifactory.py
24.78
KB
-rw-r--r--
2022-05-16 09:16
at.py
10.65
KB
-rw-r--r--
2022-05-16 09:16
at_solaris.py
8.56
KB
-rw-r--r--
2022-05-16 09:16
augeas_cfg.py
13.93
KB
-rw-r--r--
2022-05-16 09:16
aws_sqs.py
6.55
KB
-rw-r--r--
2022-05-16 09:16
azurearm_compute.py
19.55
KB
-rw-r--r--
2022-05-16 09:16
azurearm_dns.py
14.7
KB
-rw-r--r--
2022-05-16 09:16
azurearm_network.py
80.8
KB
-rw-r--r--
2022-05-16 09:16
azurearm_resource.py
34.27
KB
-rw-r--r--
2022-05-16 09:16
bamboohr.py
7.36
KB
-rw-r--r--
2022-05-16 09:16
baredoc.py
11.13
KB
-rw-r--r--
2022-05-16 09:16
bcache.py
28.97
KB
-rw-r--r--
2022-05-16 09:16
beacons.py
27.89
KB
-rw-r--r--
2022-05-16 09:16
bigip.py
69.11
KB
-rw-r--r--
2022-05-16 09:16
bluez_bluetooth.py
6.76
KB
-rw-r--r--
2022-05-16 09:16
boto3_elasticache.py
37.34
KB
-rw-r--r--
2022-05-16 09:16
boto3_elasticsearch.py
53.17
KB
-rw-r--r--
2022-05-16 09:16
boto3_route53.py
39.75
KB
-rw-r--r--
2022-05-16 09:16
boto3_sns.py
12.93
KB
-rw-r--r--
2022-05-16 09:16
boto_apigateway.py
61.86
KB
-rw-r--r--
2022-05-16 09:16
boto_asg.py
35.7
KB
-rw-r--r--
2022-05-16 09:16
boto_cfn.py
7.95
KB
-rw-r--r--
2022-05-16 09:16
boto_cloudfront.py
12.75
KB
-rw-r--r--
2022-05-16 09:16
boto_cloudtrail.py
14.45
KB
-rw-r--r--
2022-05-16 09:16
boto_cloudwatch.py
10.99
KB
-rw-r--r--
2022-05-16 09:16
boto_cloudwatch_event.py
9.48
KB
-rw-r--r--
2022-05-16 09:16
boto_cognitoidentity.py
14.63
KB
-rw-r--r--
2022-05-16 09:16
boto_datapipeline.py
6.94
KB
-rw-r--r--
2022-05-16 09:16
boto_dynamodb.py
10.54
KB
-rw-r--r--
2022-05-16 09:16
boto_ec2.py
79.29
KB
-rw-r--r--
2022-05-16 09:16
boto_efs.py
14.05
KB
-rw-r--r--
2022-05-16 09:16
boto_elasticache.py
23.69
KB
-rw-r--r--
2022-05-16 09:16
boto_elasticsearch_domain.py
15.85
KB
-rw-r--r--
2022-05-16 09:16
boto_elb.py
35.4
KB
-rw-r--r--
2022-05-16 09:16
boto_elbv2.py
10.81
KB
-rw-r--r--
2022-05-16 09:16
boto_iam.py
75.62
KB
-rw-r--r--
2022-05-16 09:16
boto_iot.py
26.2
KB
-rw-r--r--
2022-05-16 09:16
boto_kinesis.py
19.63
KB
-rw-r--r--
2022-05-16 09:16
boto_kms.py
17.29
KB
-rw-r--r--
2022-05-16 09:16
boto_lambda.py
35.05
KB
-rw-r--r--
2022-05-16 09:16
boto_rds.py
34.92
KB
-rw-r--r--
2022-05-16 09:16
boto_route53.py
32.55
KB
-rw-r--r--
2022-05-16 09:16
boto_s3.py
4.24
KB
-rw-r--r--
2022-05-16 09:16
boto_s3_bucket.py
31.8
KB
-rw-r--r--
2022-05-16 09:16
boto_secgroup.py
25.22
KB
-rw-r--r--
2022-05-16 09:16
boto_sns.py
7.22
KB
-rw-r--r--
2022-05-16 09:16
boto_sqs.py
6.43
KB
-rw-r--r--
2022-05-16 09:16
boto_ssm.py
3.65
KB
-rw-r--r--
2022-05-16 09:16
boto_vpc.py
112.81
KB
-rw-r--r--
2022-05-16 09:16
bower.py
5.89
KB
-rw-r--r--
2022-05-16 09:16
bridge.py
10.86
KB
-rw-r--r--
2022-05-16 09:16
bsd_shadow.py
6.92
KB
-rw-r--r--
2022-05-16 09:16
btrfs.py
33.64
KB
-rw-r--r--
2022-05-16 09:16
cabal.py
3.79
KB
-rw-r--r--
2022-05-16 09:16
capirca_acl.py
40.04
KB
-rw-r--r--
2022-05-16 09:16
cassandra_cql.py
39
KB
-rw-r--r--
2022-05-16 09:16
cassandra_mod.py
3.97
KB
-rw-r--r--
2022-05-16 09:16
celery.py
3.33
KB
-rw-r--r--
2022-05-16 09:16
ceph.py
15.82
KB
-rw-r--r--
2022-05-16 09:16
chassis.py
1.52
KB
-rw-r--r--
2022-05-16 09:16
chef.py
4.66
KB
-rw-r--r--
2022-05-16 09:16
chocolatey.py
39.34
KB
-rw-r--r--
2022-05-16 09:16
chronos.py
2.89
KB
-rw-r--r--
2022-05-16 09:16
chroot.py
11.51
KB
-rw-r--r--
2022-05-16 09:16
cimc.py
23.02
KB
-rw-r--r--
2022-05-16 09:16
ciscoconfparse_mod.py
14.79
KB
-rw-r--r--
2022-05-16 09:16
cisconso.py
3.83
KB
-rw-r--r--
2022-05-16 09:16
cloud.py
9.39
KB
-rw-r--r--
2022-05-16 09:16
cmdmod.py
162.16
KB
-rw-r--r--
2022-05-16 09:16
composer.py
10.31
KB
-rw-r--r--
2022-05-16 09:16
config.py
16.85
KB
-rw-r--r--
2022-05-16 09:16
consul.py
68.93
KB
-rw-r--r--
2022-05-16 09:16
container_resource.py
13.36
KB
-rw-r--r--
2022-05-16 09:16
cp.py
27.98
KB
-rw-r--r--
2022-05-16 09:16
cpan.py
5.54
KB
-rw-r--r--
2022-05-16 09:16
cron.py
26.8
KB
-rw-r--r--
2022-05-16 09:16
cryptdev.py
10.08
KB
-rw-r--r--
2022-05-16 09:16
csf.py
16.04
KB
-rw-r--r--
2022-05-16 09:16
cyg.py
8.32
KB
-rw-r--r--
2022-05-16 09:16
daemontools.py
5.41
KB
-rw-r--r--
2022-05-16 09:16
data.py
3.83
KB
-rw-r--r--
2022-05-16 09:16
datadog_api.py
7.64
KB
-rw-r--r--
2022-05-16 09:16
ddns.py
7.04
KB
-rw-r--r--
2022-05-16 09:16
deb_apache.py
7.41
KB
-rw-r--r--
2022-05-16 09:16
deb_postgres.py
4.22
KB
-rw-r--r--
2022-05-16 09:16
debconfmod.py
4.06
KB
-rw-r--r--
2022-05-16 09:16
debian_ip.py
64.78
KB
-rw-r--r--
2022-05-16 09:16
debian_service.py
6.6
KB
-rw-r--r--
2022-05-16 09:16
debuild_pkgbuild.py
34.69
KB
-rw-r--r--
2022-05-16 09:16
defaults.py
5.42
KB
-rw-r--r--
2022-05-16 09:16
devinfo.py
9.05
KB
-rw-r--r--
2022-05-16 09:16
devmap.py
627
B
-rw-r--r--
2022-05-16 09:16
dig.py
7.45
KB
-rw-r--r--
2022-05-16 09:16
disk.py
30.44
KB
-rw-r--r--
2022-05-16 09:16
djangomod.py
7.53
KB
-rw-r--r--
2022-05-16 09:16
dnsmasq.py
5.71
KB
-rw-r--r--
2022-05-16 09:16
dnsutil.py
11.51
KB
-rw-r--r--
2022-05-16 09:16
dockercompose.py
32.62
KB
-rw-r--r--
2022-05-16 09:16
dockermod.py
224.97
KB
-rw-r--r--
2022-05-16 09:16
dpkg_lowpkg.py
12.9
KB
-rw-r--r--
2022-05-16 09:16
drac.py
10.97
KB
-rw-r--r--
2022-05-16 09:16
dracr.py
38.53
KB
-rw-r--r--
2022-05-16 09:16
drbd.py
7.19
KB
-rw-r--r--
2022-05-16 09:16
dummyproxy_pkg.py
2.46
KB
-rw-r--r--
2022-05-16 09:16
dummyproxy_service.py
2.91
KB
-rw-r--r--
2022-05-16 09:16
ebuildpkg.py
38.74
KB
-rw-r--r--
2022-05-16 09:16
eix.py
1.58
KB
-rw-r--r--
2022-05-16 09:16
elasticsearch.py
51.44
KB
-rw-r--r--
2022-05-16 09:16
environ.py
8.96
KB
-rw-r--r--
2022-05-16 09:16
eselect.py
4.99
KB
-rw-r--r--
2022-05-16 09:16
esxcluster.py
502
B
-rw-r--r--
2022-05-16 09:16
esxdatacenter.py
514
B
-rw-r--r--
2022-05-16 09:16
esxi.py
1.64
KB
-rw-r--r--
2022-05-16 09:16
esxvm.py
481
B
-rw-r--r--
2022-05-16 09:16
etcd_mod.py
7.02
KB
-rw-r--r--
2022-05-16 09:16
ethtool.py
7.65
KB
-rw-r--r--
2022-05-16 09:16
event.py
8.23
KB
-rw-r--r--
2022-05-16 09:16
extfs.py
8.78
KB
-rw-r--r--
2022-05-16 09:16
file.py
224.74
KB
-rw-r--r--
2022-05-16 09:16
firewalld.py
20.51
KB
-rw-r--r--
2022-05-16 09:16
freebsd_sysctl.py
4.76
KB
-rw-r--r--
2022-05-16 09:16
freebsd_update.py
6.19
KB
-rw-r--r--
2022-05-16 09:16
freebsdjail.py
7.16
KB
-rw-r--r--
2022-05-16 09:16
freebsdkmod.py
6.17
KB
-rw-r--r--
2022-05-16 09:16
freebsdpkg.py
17.04
KB
-rw-r--r--
2022-05-16 09:16
freebsdports.py
13.13
KB
-rw-r--r--
2022-05-16 09:16
freebsdservice.py
12.53
KB
-rw-r--r--
2022-05-16 09:16
freezer.py
8.91
KB
-rw-r--r--
2022-05-16 09:16
gcp_addon.py
4.07
KB
-rw-r--r--
2022-05-16 09:16
gem.py
10.6
KB
-rw-r--r--
2022-05-16 09:16
genesis.py
21.75
KB
-rw-r--r--
2022-05-16 09:16
gentoo_service.py
9.18
KB
-rw-r--r--
2022-05-16 09:16
gentoolkitmod.py
8.33
KB
-rw-r--r--
2022-05-16 09:16
git.py
171.44
KB
-rw-r--r--
2022-05-16 09:16
github.py
53.19
KB
-rw-r--r--
2022-05-16 09:16
glanceng.py
4.69
KB
-rw-r--r--
2022-05-16 09:16
glassfish.py
19.49
KB
-rw-r--r--
2022-05-16 09:16
glusterfs.py
19.55
KB
-rw-r--r--
2022-05-16 09:16
gnomedesktop.py
6.85
KB
-rw-r--r--
2022-05-16 09:16
google_chat.py
1.52
KB
-rw-r--r--
2022-05-16 09:16
gpg.py
39.99
KB
-rw-r--r--
2022-05-16 09:16
grafana4.py
30.27
KB
-rw-r--r--
2022-05-16 09:16
grains.py
23.67
KB
-rw-r--r--
2022-05-16 09:16
groupadd.py
10.85
KB
-rw-r--r--
2022-05-16 09:16
grub_legacy.py
3.08
KB
-rw-r--r--
2022-05-16 09:16
guestfs.py
2.32
KB
-rw-r--r--
2022-05-16 09:16
hadoop.py
3.76
KB
-rw-r--r--
2022-05-16 09:16
haproxyconn.py
10.17
KB
-rw-r--r--
2022-05-16 09:16
hashutil.py
6.77
KB
-rw-r--r--
2022-05-16 09:16
heat.py
25.26
KB
-rw-r--r--
2022-05-16 09:16
helm.py
39.27
KB
-rw-r--r--
2022-05-16 09:16
hg.py
7.16
KB
-rw-r--r--
2022-05-16 09:16
highstate_doc.py
22.76
KB
-rw-r--r--
2022-05-16 09:16
hosts.py
10.47
KB
-rw-r--r--
2022-05-16 09:16
http.py
3.75
KB
-rw-r--r--
2022-05-16 09:16
icinga2.py
4.46
KB
-rw-r--r--
2022-05-16 09:16
idem.py
1.75
KB
-rw-r--r--
2022-05-16 09:16
ifttt.py
2.28
KB
-rw-r--r--
2022-05-16 09:16
ilo.py
15.98
KB
-rw-r--r--
2022-05-16 09:16
incron.py
7.68
KB
-rw-r--r--
2022-05-16 09:16
influxdb08mod.py
15.07
KB
-rw-r--r--
2022-05-16 09:16
influxdbmod.py
16.13
KB
-rw-r--r--
2022-05-16 09:16
infoblox.py
17.53
KB
-rw-r--r--
2022-05-16 09:16
ini_manage.py
14.63
KB
-rw-r--r--
2022-05-16 09:16
inspector.py
8.19
KB
-rw-r--r--
2022-05-16 09:16
introspect.py
4.02
KB
-rw-r--r--
2022-05-16 09:16
iosconfig.py
14.78
KB
-rw-r--r--
2022-05-16 09:16
ipmi.py
25.45
KB
-rw-r--r--
2022-05-16 09:16
ipset.py
17.97
KB
-rw-r--r--
2022-05-16 09:16
iptables.py
57.33
KB
-rw-r--r--
2022-05-16 09:16
iwtools.py
3.99
KB
-rw-r--r--
2022-05-16 09:16
jboss7.py
20.51
KB
-rw-r--r--
2022-05-16 09:16
jboss7_cli.py
15.23
KB
-rw-r--r--
2022-05-16 09:16
jenkinsmod.py
11.9
KB
-rw-r--r--
2022-05-16 09:16
jinja.py
2.66
KB
-rw-r--r--
2022-05-16 09:16
jira_mod.py
7.07
KB
-rw-r--r--
2022-05-16 09:16
junos.py
73.9
KB
-rw-r--r--
2022-05-16 09:16
k8s.py
24.87
KB
-rw-r--r--
2022-05-16 09:16
kapacitor.py
5.37
KB
-rw-r--r--
2022-05-16 09:16
kerberos.py
5.42
KB
-rw-r--r--
2022-05-16 09:16
kernelpkg_linux_apt.py
6.91
KB
-rw-r--r--
2022-05-16 09:16
kernelpkg_linux_yum.py
7.46
KB
-rw-r--r--
2022-05-16 09:16
key.py
1007
B
-rw-r--r--
2022-05-16 09:16
keyboard.py
2.64
KB
-rw-r--r--
2022-05-16 09:16
keystone.py
43.16
KB
-rw-r--r--
2022-05-16 09:16
keystoneng.py
21.82
KB
-rw-r--r--
2022-05-16 09:16
keystore.py
6.69
KB
-rw-r--r--
2022-05-16 09:16
kmod.py
7.29
KB
-rw-r--r--
2022-05-16 09:16
kubeadm.py
34.01
KB
-rw-r--r--
2022-05-16 09:16
kubernetesmod.py
46.66
KB
-rw-r--r--
2022-05-16 09:16
launchctl_service.py
9.73
KB
-rw-r--r--
2022-05-16 09:16
layman.py
4.22
KB
-rw-r--r--
2022-05-16 09:16
ldap3.py
18.81
KB
-rw-r--r--
2022-05-16 09:16
ldapmod.py
5.9
KB
-rw-r--r--
2022-05-16 09:16
libcloud_compute.py
23.51
KB
-rw-r--r--
2022-05-16 09:16
libcloud_dns.py
9.76
KB
-rw-r--r--
2022-05-16 09:16
libcloud_loadbalancer.py
13.17
KB
-rw-r--r--
2022-05-16 09:16
libcloud_storage.py
12.19
KB
-rw-r--r--
2022-05-16 09:16
linux_acl.py
7.7
KB
-rw-r--r--
2022-05-16 09:16
linux_ip.py
5.44
KB
-rw-r--r--
2022-05-16 09:16
linux_lvm.py
17.86
KB
-rw-r--r--
2022-05-16 09:16
linux_service.py
4.64
KB
-rw-r--r--
2022-05-16 09:16
linux_shadow.py
13.37
KB
-rw-r--r--
2022-05-16 09:16
linux_sysctl.py
7.39
KB
-rw-r--r--
2022-05-16 09:16
localemod.py
11.84
KB
-rw-r--r--
2022-05-16 09:16
locate.py
2.58
KB
-rw-r--r--
2022-05-16 09:16
logadm.py
9.57
KB
-rw-r--r--
2022-05-16 09:16
logmod.py
1.24
KB
-rw-r--r--
2022-05-16 09:16
logrotate.py
7.72
KB
-rw-r--r--
2022-05-16 09:16
lvs.py
11.54
KB
-rw-r--r--
2022-05-16 09:16
lxc.py
148.61
KB
-rw-r--r--
2022-05-16 09:16
lxd.py
90.2
KB
-rw-r--r--
2022-05-16 09:16
mac_assistive.py
6.36
KB
-rw-r--r--
2022-05-16 09:16
mac_brew_pkg.py
19.82
KB
-rw-r--r--
2022-05-16 09:16
mac_desktop.py
2.77
KB
-rw-r--r--
2022-05-16 09:16
mac_group.py
6.34
KB
-rw-r--r--
2022-05-16 09:16
mac_keychain.py
6.68
KB
-rw-r--r--
2022-05-16 09:16
mac_pkgutil.py
2.84
KB
-rw-r--r--
2022-05-16 09:16
mac_portspkg.py
11.36
KB
-rw-r--r--
2022-05-16 09:16
mac_power.py
13.29
KB
-rw-r--r--
2022-05-16 09:16
mac_service.py
19.64
KB
-rw-r--r--
2022-05-16 09:16
mac_shadow.py
14.23
KB
-rw-r--r--
2022-05-16 09:16
mac_softwareupdate.py
14.52
KB
-rw-r--r--
2022-05-16 09:16
mac_sysctl.py
5.13
KB
-rw-r--r--
2022-05-16 09:16
mac_system.py
15.2
KB
-rw-r--r--
2022-05-16 09:16
mac_timezone.py
8.34
KB
-rw-r--r--
2022-05-16 09:16
mac_user.py
16.36
KB
-rw-r--r--
2022-05-16 09:16
mac_xattr.py
6.11
KB
-rw-r--r--
2022-05-16 09:16
macdefaults.py
2.33
KB
-rw-r--r--
2022-05-16 09:16
macpackage.py
6.94
KB
-rw-r--r--
2022-05-16 09:16
makeconf.py
17.31
KB
-rw-r--r--
2022-05-16 09:16
mandrill.py
6.31
KB
-rw-r--r--
2022-05-16 09:16
marathon.py
5.36
KB
-rw-r--r--
2022-05-16 09:16
match.py
10.28
KB
-rw-r--r--
2022-05-16 09:16
mattermost.py
3.4
KB
-rw-r--r--
2022-05-16 09:16
mdadm_raid.py
9.86
KB
-rw-r--r--
2022-05-16 09:16
mdata.py
3.44
KB
-rw-r--r--
2022-05-16 09:16
memcached.py
6.13
KB
-rw-r--r--
2022-05-16 09:16
mine.py
18.79
KB
-rw-r--r--
2022-05-16 09:16
minion.py
7.68
KB
-rw-r--r--
2022-05-16 09:16
mod_random.py
6.72
KB
-rw-r--r--
2022-05-16 09:16
modjk.py
12.48
KB
-rw-r--r--
2022-05-16 09:16
mongodb.py
17.3
KB
-rw-r--r--
2022-05-16 09:16
monit.py
5.51
KB
-rw-r--r--
2022-05-16 09:16
moosefs.py
3.87
KB
-rw-r--r--
2022-05-16 09:16
mount.py
56.18
KB
-rw-r--r--
2022-05-16 09:16
mssql.py
14.64
KB
-rw-r--r--
2022-05-16 09:16
msteams.py
2
KB
-rw-r--r--
2022-05-16 09:16
munin.py
2.4
KB
-rw-r--r--
2022-05-16 09:16
mysql.py
87.85
KB
-rw-r--r--
2022-05-16 09:16
nacl.py
9.73
KB
-rw-r--r--
2022-05-16 09:16
nagios.py
6.53
KB
-rw-r--r--
2022-05-16 09:16
nagios_rpc.py
5.09
KB
-rw-r--r--
2022-05-16 09:16
namecheap_domains.py
12.84
KB
-rw-r--r--
2022-05-16 09:16
namecheap_domains_dns.py
5.93
KB
-rw-r--r--
2022-05-16 09:16
namecheap_domains_ns.py
4.51
KB
-rw-r--r--
2022-05-16 09:16
namecheap_ssl.py
25.72
KB
-rw-r--r--
2022-05-16 09:16
namecheap_users.py
2.4
KB
-rw-r--r--
2022-05-16 09:16
napalm_bgp.py
9.72
KB
-rw-r--r--
2022-05-16 09:16
napalm_formula.py
11.33
KB
-rw-r--r--
2022-05-16 09:16
napalm_mod.py
59.3
KB
-rw-r--r--
2022-05-16 09:16
napalm_netacl.py
28.59
KB
-rw-r--r--
2022-05-16 09:16
napalm_network.py
93.24
KB
-rw-r--r--
2022-05-16 09:16
napalm_ntp.py
10.22
KB
-rw-r--r--
2022-05-16 09:16
napalm_probes.py
13.25
KB
-rw-r--r--
2022-05-16 09:16
napalm_route.py
5.09
KB
-rw-r--r--
2022-05-16 09:16
napalm_snmp.py
7.05
KB
-rw-r--r--
2022-05-16 09:16
napalm_users.py
6.49
KB
-rw-r--r--
2022-05-16 09:16
napalm_yang_mod.py
20.28
KB
-rw-r--r--
2022-05-16 09:16
netaddress.py
1.6
KB
-rw-r--r--
2022-05-16 09:16
netbox.py
32.22
KB
-rw-r--r--
2022-05-16 09:16
netbsd_sysctl.py
3.97
KB
-rw-r--r--
2022-05-16 09:16
netbsdservice.py
6.49
KB
-rw-r--r--
2022-05-16 09:16
netmiko_mod.py
19.63
KB
-rw-r--r--
2022-05-16 09:16
netscaler.py
27.02
KB
-rw-r--r--
2022-05-16 09:16
network.py
62.75
KB
-rw-r--r--
2022-05-16 09:16
neutron.py
44.93
KB
-rw-r--r--
2022-05-16 09:16
neutronng.py
15.02
KB
-rw-r--r--
2022-05-16 09:16
nexus.py
22.95
KB
-rw-r--r--
2022-05-16 09:16
nfs3.py
3.9
KB
-rw-r--r--
2022-05-16 09:16
nftables.py
33.58
KB
-rw-r--r--
2022-05-16 09:16
nginx.py
3.83
KB
-rw-r--r--
2022-05-16 09:16
nilrt_ip.py
36.18
KB
-rw-r--r--
2022-05-16 09:16
nix.py
8.03
KB
-rw-r--r--
2022-05-16 09:16
nova.py
19.61
KB
-rw-r--r--
2022-05-16 09:16
npm.py
10.35
KB
-rw-r--r--
2022-05-16 09:16
nspawn.py
41.35
KB
-rw-r--r--
2022-05-16 09:16
nxos.py
24.67
KB
-rw-r--r--
2022-05-16 09:16
nxos_api.py
14.66
KB
-rw-r--r--
2022-05-16 09:16
nxos_upgrade.py
14.74
KB
-rw-r--r--
2022-05-16 09:16
omapi.py
3.6
KB
-rw-r--r--
2022-05-16 09:16
openbsd_sysctl.py
3.74
KB
-rw-r--r--
2022-05-16 09:16
openbsdpkg.py
11
KB
-rw-r--r--
2022-05-16 09:16
openbsdrcctl_service.py
6.25
KB
-rw-r--r--
2022-05-16 09:16
openbsdservice.py
8.31
KB
-rw-r--r--
2022-05-16 09:16
openscap.py
2.81
KB
-rw-r--r--
2022-05-16 09:16
openstack_config.py
3.5
KB
-rw-r--r--
2022-05-16 09:16
openstack_mng.py
2.71
KB
-rw-r--r--
2022-05-16 09:16
openvswitch.py
11.75
KB
-rw-r--r--
2022-05-16 09:16
opkg.py
49.72
KB
-rw-r--r--
2022-05-16 09:16
opsgenie.py
3.29
KB
-rw-r--r--
2022-05-16 09:16
oracle.py
5.83
KB
-rw-r--r--
2022-05-16 09:16
osquery.py
24.93
KB
-rw-r--r--
2022-05-16 09:16
out.py
2.53
KB
-rw-r--r--
2022-05-16 09:16
pacmanpkg.py
31.99
KB
-rw-r--r--
2022-05-16 09:16
pagerduty.py
4.7
KB
-rw-r--r--
2022-05-16 09:16
pagerduty_util.py
13.49
KB
-rw-r--r--
2022-05-16 09:16
pam.py
2.01
KB
-rw-r--r--
2022-05-16 09:16
panos.py
61.05
KB
-rw-r--r--
2022-05-16 09:16
parallels.py
19.85
KB
-rw-r--r--
2022-05-16 09:16
parted_partition.py
21.53
KB
-rw-r--r--
2022-05-16 09:16
pcs.py
14.11
KB
-rw-r--r--
2022-05-16 09:16
pdbedit.py
10.72
KB
-rw-r--r--
2022-05-16 09:16
pecl.py
3.79
KB
-rw-r--r--
2022-05-16 09:16
peeringdb.py
8.39
KB
-rw-r--r--
2022-05-16 09:16
pf.py
9.51
KB
-rw-r--r--
2022-05-16 09:16
philips_hue.py
1.55
KB
-rw-r--r--
2022-05-16 09:16
pillar.py
21.29
KB
-rw-r--r--
2022-05-16 09:16
pip.py
51.76
KB
-rw-r--r--
2022-05-16 09:16
pkg_resource.py
11.89
KB
-rw-r--r--
2022-05-16 09:16
pkgin.py
17.35
KB
-rw-r--r--
2022-05-16 09:16
pkgng.py
61.1
KB
-rw-r--r--
2022-05-16 09:16
pkgutil.py
9.88
KB
-rw-r--r--
2022-05-16 09:16
portage_config.py
22.77
KB
-rw-r--r--
2022-05-16 09:16
postfix.py
16.24
KB
-rw-r--r--
2022-05-16 09:16
postgres.py
88.3
KB
-rw-r--r--
2022-05-16 09:16
poudriere.py
7.85
KB
-rw-r--r--
2022-05-16 09:16
powerpath.py
2.57
KB
-rw-r--r--
2022-05-16 09:16
proxy.py
11.49
KB
-rw-r--r--
2022-05-16 09:16
ps.py
19.45
KB
-rw-r--r--
2022-05-16 09:16
publish.py
10.22
KB
-rw-r--r--
2022-05-16 09:16
puppet.py
11.69
KB
-rw-r--r--
2022-05-16 09:16
purefa.py
33.03
KB
-rw-r--r--
2022-05-16 09:16
purefb.py
13.65
KB
-rw-r--r--
2022-05-16 09:16
pushbullet.py
1.88
KB
-rw-r--r--
2022-05-16 09:16
pushover_notify.py
3.48
KB
-rw-r--r--
2022-05-16 09:16
pw_group.py
4.4
KB
-rw-r--r--
2022-05-16 09:16
pw_user.py
12.47
KB
-rw-r--r--
2022-05-16 09:16
pyenv.py
6.93
KB
-rw-r--r--
2022-05-16 09:16
qemu_img.py
1.53
KB
-rw-r--r--
2022-05-16 09:16
qemu_nbd.py
3.28
KB
-rw-r--r--
2022-05-16 09:16
quota.py
6.43
KB
-rw-r--r--
2022-05-16 09:16
rabbitmq.py
38.44
KB
-rw-r--r--
2022-05-16 09:16
rallydev.py
6.09
KB
-rw-r--r--
2022-05-16 09:16
random_org.py
23.76
KB
-rw-r--r--
2022-05-16 09:16
rbac_solaris.py
16.15
KB
-rw-r--r--
2022-05-16 09:16
rbenv.py
10.75
KB
-rw-r--r--
2022-05-16 09:16
rdp.py
6.08
KB
-rw-r--r--
2022-05-16 09:16
rebootmgr.py
7.66
KB
-rw-r--r--
2022-05-16 09:16
redismod.py
16.36
KB
-rw-r--r--
2022-05-16 09:16
reg.py
16.36
KB
-rw-r--r--
2022-05-16 09:16
rest_pkg.py
2.26
KB
-rw-r--r--
2022-05-16 09:16
rest_sample_utils.py
558
B
-rw-r--r--
2022-05-16 09:16
rest_service.py
3.63
KB
-rw-r--r--
2022-05-16 09:16
restartcheck.py
24.1
KB
-rw-r--r--
2022-05-16 09:16
ret.py
1.27
KB
-rw-r--r--
2022-05-16 09:16
rh_ip.py
38.01
KB
-rw-r--r--
2022-05-16 09:16
rh_service.py
16.61
KB
-rw-r--r--
2022-05-16 09:16
riak.py
5.19
KB
-rw-r--r--
2022-05-16 09:16
rpm_lowpkg.py
27.61
KB
-rw-r--r--
2022-05-16 09:16
rpmbuild_pkgbuild.py
24.53
KB
-rw-r--r--
2022-05-16 09:16
rsync.py
8.04
KB
-rw-r--r--
2022-05-16 09:16
runit.py
17.14
KB
-rw-r--r--
2022-05-16 09:16
rvm.py
11.1
KB
-rw-r--r--
2022-05-16 09:16
s3.py
9.93
KB
-rw-r--r--
2022-05-16 09:16
s6.py
3.62
KB
-rw-r--r--
2022-05-16 09:16
salt_proxy.py
4.48
KB
-rw-r--r--
2022-05-16 09:16
salt_version.py
4.29
KB
-rw-r--r--
2022-05-16 09:16
saltcheck.py
46.11
KB
-rw-r--r--
2022-05-16 09:16
saltcloudmod.py
954
B
-rw-r--r--
2022-05-16 09:16
saltutil.py
56.5
KB
-rw-r--r--
2022-05-16 09:16
schedule.py
43.35
KB
-rw-r--r--
2022-05-16 09:16
scp_mod.py
6.22
KB
-rw-r--r--
2022-05-16 09:16
scsi.py
2.66
KB
-rw-r--r--
2022-05-16 09:16
sdb.py
2.45
KB
-rw-r--r--
2022-05-16 09:16
seed.py
8.87
KB
-rw-r--r--
2022-05-16 09:16
selinux.py
23.83
KB
-rw-r--r--
2022-05-16 09:16
sensehat.py
7.79
KB
-rw-r--r--
2022-05-16 09:16
sensors.py
1.3
KB
-rw-r--r--
2022-05-16 09:16
serverdensity_device.py
8.1
KB
-rw-r--r--
2022-05-16 09:16
servicenow.py
4.38
KB
-rw-r--r--
2022-05-16 09:16
slack_notify.py
7.83
KB
-rw-r--r--
2022-05-16 09:16
slackware_service.py
6.89
KB
-rw-r--r--
2022-05-16 09:16
slsutil.py
19.05
KB
-rw-r--r--
2022-05-16 09:16
smartos_imgadm.py
12.09
KB
-rw-r--r--
2022-05-16 09:16
smartos_nictagadm.py
6.51
KB
-rw-r--r--
2022-05-16 09:16
smartos_virt.py
5.21
KB
-rw-r--r--
2022-05-16 09:16
smartos_vmadm.py
26.37
KB
-rw-r--r--
2022-05-16 09:16
smbios.py
10.06
KB
-rw-r--r--
2022-05-16 09:16
smf_service.py
8.52
KB
-rw-r--r--
2022-05-16 09:16
smtp.py
5.41
KB
-rw-r--r--
2022-05-16 09:16
snapper.py
27.14
KB
-rw-r--r--
2022-05-16 09:16
solaris_fmadm.py
11.27
KB
-rw-r--r--
2022-05-16 09:16
solaris_group.py
2.8
KB
-rw-r--r--
2022-05-16 09:16
solaris_shadow.py
7.98
KB
-rw-r--r--
2022-05-16 09:16
solaris_system.py
3.72
KB
-rw-r--r--
2022-05-16 09:16
solaris_user.py
11.06
KB
-rw-r--r--
2022-05-16 09:16
solarisipspkg.py
18.7
KB
-rw-r--r--
2022-05-16 09:16
solarispkg.py
15.42
KB
-rw-r--r--
2022-05-16 09:16
solr.py
45.54
KB
-rw-r--r--
2022-05-16 09:16
solrcloud.py
14.63
KB
-rw-r--r--
2022-05-16 09:16
splunk.py
8.15
KB
-rw-r--r--
2022-05-16 09:16
splunk_search.py
8.76
KB
-rw-r--r--
2022-05-16 09:16
sqlite3.py
2.54
KB
-rw-r--r--
2022-05-16 09:16
ssh.py
43.15
KB
-rw-r--r--
2022-05-16 09:16
ssh_pkg.py
1.08
KB
-rw-r--r--
2022-05-16 09:16
ssh_service.py
3.39
KB
-rw-r--r--
2022-05-16 09:16
state.py
78.55
KB
-rw-r--r--
2022-05-16 09:16
status.py
57.34
KB
-rw-r--r--
2022-05-16 09:16
statuspage.py
14.67
KB
-rw-r--r--
2022-05-16 09:16
supervisord.py
11.15
KB
-rw-r--r--
2022-05-16 09:16
suse_apache.py
2.45
KB
-rw-r--r--
2022-05-16 09:16
svn.py
10.75
KB
-rw-r--r--
2022-05-16 09:16
swarm.py
13.5
KB
-rw-r--r--
2022-05-16 09:16
swift.py
5.55
KB
-rw-r--r--
2022-05-16 09:16
sysbench.py
6.62
KB
-rw-r--r--
2022-05-16 09:16
sysfs.py
6.61
KB
-rw-r--r--
2022-05-16 09:16
syslog_ng.py
31.55
KB
-rw-r--r--
2022-05-16 09:16
sysmod.py
22.59
KB
-rw-r--r--
2022-05-16 09:16
sysrc.py
3.38
KB
-rw-r--r--
2022-05-16 09:16
system.py
19.28
KB
-rw-r--r--
2022-05-16 09:16
system_profiler.py
3.54
KB
-rw-r--r--
2022-05-16 09:16
systemd_service.py
46.19
KB
-rw-r--r--
2022-05-16 09:16
telegram.py
3.28
KB
-rw-r--r--
2022-05-16 09:16
telemetry.py
12.9
KB
-rw-r--r--
2022-05-16 09:16
temp.py
831
B
-rw-r--r--
2022-05-16 09:16
test.py
14.71
KB
-rw-r--r--
2022-05-16 09:16
test_virtual.py
194
B
-rw-r--r--
2022-05-16 09:16
testinframod.py
9.92
KB
-rw-r--r--
2022-05-16 09:16
textfsm_mod.py
16.22
KB
-rw-r--r--
2022-05-16 09:16
timezone.py
19.89
KB
-rw-r--r--
2022-05-16 09:16
tls.py
58.67
KB
-rw-r--r--
2022-05-16 09:16
tomcat.py
18.59
KB
-rw-r--r--
2022-05-16 09:16
trafficserver.py
10.44
KB
-rw-r--r--
2022-05-16 09:16
transactional_update.py
42
KB
-rw-r--r--
2022-05-16 09:16
travisci.py
2.08
KB
-rw-r--r--
2022-05-16 09:16
tuned.py
2.34
KB
-rw-r--r--
2022-05-16 09:16
twilio_notify.py
2.95
KB
-rw-r--r--
2022-05-16 09:16
udev.py
3.72
KB
-rw-r--r--
2022-05-16 09:16
upstart_service.py
16.92
KB
-rw-r--r--
2022-05-16 09:16
uptime.py
3.23
KB
-rw-r--r--
2022-05-16 09:16
useradd.py
22.3
KB
-rw-r--r--
2022-05-16 09:16
uwsgi.py
996
B
-rw-r--r--
2022-05-16 09:16
vagrant.py
20.4
KB
-rw-r--r--
2022-05-16 09:16
varnish.py
3.08
KB
-rw-r--r--
2022-05-16 09:16
vault.py
13.48
KB
-rw-r--r--
2022-05-16 09:16
vbox_guest.py
10.55
KB
-rw-r--r--
2022-05-16 09:16
vboxmanage.py
14.72
KB
-rw-r--r--
2022-05-16 09:16
vcenter.py
455
B
-rw-r--r--
2022-05-16 09:16
victorops.py
6.54
KB
-rw-r--r--
2022-05-16 09:16
virt.py
290.11
KB
-rw-r--r--
2022-05-16 09:16
virtualenv_mod.py
15.08
KB
-rw-r--r--
2022-05-16 09:16
vmctl.py
9.6
KB
-rw-r--r--
2022-05-16 09:16
vsphere.py
376.7
KB
-rw-r--r--
2022-05-16 09:16
webutil.py
3.66
KB
-rw-r--r--
2022-05-16 09:16
win_auditpol.py
4.74
KB
-rw-r--r--
2022-05-16 09:16
win_autoruns.py
2.29
KB
-rw-r--r--
2022-05-16 09:16
win_certutil.py
3.27
KB
-rw-r--r--
2022-05-16 09:16
win_dacl.py
32.27
KB
-rw-r--r--
2022-05-16 09:16
win_disk.py
1.8
KB
-rw-r--r--
2022-05-16 09:16
win_dism.py
18.26
KB
-rw-r--r--
2022-05-16 09:16
win_dns_client.py
4.19
KB
-rw-r--r--
2022-05-16 09:16
win_dsc.py
26.56
KB
-rw-r--r--
2022-05-16 09:16
win_file.py
59.46
KB
-rw-r--r--
2022-05-16 09:16
win_firewall.py
20.15
KB
-rw-r--r--
2022-05-16 09:16
win_groupadd.py
11.27
KB
-rw-r--r--
2022-05-16 09:16
win_iis.py
68.76
KB
-rw-r--r--
2022-05-16 09:16
win_ip.py
11.43
KB
-rw-r--r--
2022-05-16 09:16
win_lgpo.py
491.78
KB
-rw-r--r--
2022-05-16 09:16
win_license.py
2.72
KB
-rw-r--r--
2022-05-16 09:16
win_network.py
14.02
KB
-rw-r--r--
2022-05-16 09:16
win_ntp.py
1.8
KB
-rw-r--r--
2022-05-16 09:16
win_path.py
11.12
KB
-rw-r--r--
2022-05-16 09:16
win_pkg.py
84.64
KB
-rw-r--r--
2022-05-16 09:16
win_pki.py
15.8
KB
-rw-r--r--
2022-05-16 09:16
win_powercfg.py
9.85
KB
-rw-r--r--
2022-05-16 09:16
win_psget.py
8.97
KB
-rw-r--r--
2022-05-16 09:16
win_servermanager.py
14.33
KB
-rw-r--r--
2022-05-16 09:16
win_service.py
32.7
KB
-rw-r--r--
2022-05-16 09:16
win_shadow.py
3.03
KB
-rw-r--r--
2022-05-16 09:16
win_smtp_server.py
17.67
KB
-rw-r--r--
2022-05-16 09:16
win_snmp.py
13.38
KB
-rw-r--r--
2022-05-16 09:16
win_status.py
17.04
KB
-rw-r--r--
2022-05-16 09:16
win_system.py
40.62
KB
-rw-r--r--
2022-05-16 09:16
win_task.py
78.46
KB
-rw-r--r--
2022-05-16 09:16
win_timezone.py
13.27
KB
-rw-r--r--
2022-05-16 09:16
win_useradd.py
27.53
KB
-rw-r--r--
2022-05-16 09:16
win_wua.py
38.29
KB
-rw-r--r--
2022-05-16 09:16
win_wusa.py
5.88
KB
-rw-r--r--
2022-05-16 09:16
winrepo.py
6.3
KB
-rw-r--r--
2022-05-16 09:16
wordpress.py
4.71
KB
-rw-r--r--
2022-05-16 09:16
x509.py
62.22
KB
-rw-r--r--
2022-05-16 09:16
xapi_virt.py
24.08
KB
-rw-r--r--
2022-05-16 09:16
xbpspkg.py
15.89
KB
-rw-r--r--
2022-05-16 09:16
xfs.py
15.33
KB
-rw-r--r--
2022-05-16 09:16
xml.py
2.14
KB
-rw-r--r--
2022-05-16 09:16
xmpp.py
5.28
KB
-rw-r--r--
2022-05-16 09:16
yumpkg.py
112.71
KB
-rw-r--r--
2022-05-16 09:16
zabbix.py
94.11
KB
-rw-r--r--
2022-05-16 09:16
zcbuildout.py
28.19
KB
-rw-r--r--
2022-05-16 09:16
zenoss.py
5.64
KB
-rw-r--r--
2022-05-16 09:16
zfs.py
34.49
KB
-rw-r--r--
2022-05-16 09:16
zk_concurrency.py
11.19
KB
-rw-r--r--
2022-05-16 09:16
znc.py
2.26
KB
-rw-r--r--
2022-05-16 09:16
zoneadm.py
15.11
KB
-rw-r--r--
2022-05-16 09:16
zonecfg.py
21.91
KB
-rw-r--r--
2022-05-16 09:16
zookeeper.py
14.72
KB
-rw-r--r--
2022-05-16 09:16
zpool.py
44.02
KB
-rw-r--r--
2022-05-16 09:16
zypperpkg.py
90.34
KB
-rw-r--r--
2022-05-16 09:16
Save
Rename
""" Microsoft IIS site management via WebAdministration powershell module :maintainer: Shane Lee <slee@saltstack.com>, Robert Booth <rbooth@saltstack.com> :platform: Windows :depends: PowerShell :depends: WebAdministration module (PowerShell) (IIS) .. versionadded:: 2016.3.0 """ import decimal import logging import os import re import salt.utils.json import salt.utils.platform import yaml from salt.exceptions import CommandExecutionError, SaltInvocationError log = logging.getLogger(__name__) _DEFAULT_APP = "/" _VALID_PROTOCOLS = ("ftp", "http", "https") _VALID_SSL_FLAGS = tuple(range(0, 4)) # Define the module's virtual name __virtualname__ = "win_iis" def __virtual__(): """ Load only on Windows Requires PowerShell and the WebAdministration module """ if not salt.utils.platform.is_windows(): return False, "Only available on Windows systems" powershell_info = __salt__["cmd.shell_info"]("powershell", True) if not powershell_info["installed"]: return False, "PowerShell not available" if "WebAdministration" not in powershell_info["modules"]: return False, "IIS is not installed" return __virtualname__ def _get_binding_info(host_header="", ip_address="*", port=80): """ Combine the host header, IP address, and TCP port into bindingInformation format. Binding Information specifies information to communicate with a site. It includes the IP address, the port number, and an optional host header (usually a host name) to communicate with the site. Args: host_header (str): Usually a hostname ip_address (str): The IP address port (int): The port Returns: str: A properly formatted bindingInformation string (IP:port:hostheader) eg: 192.168.0.12:80:www.contoso.com """ return ":".join([ip_address, str(port), host_header.replace(" ", "")]) def _list_certs(certificate_store="My"): """ List details of available certificates in the LocalMachine certificate store. Args: certificate_store (str): The name of the certificate store on the local machine. Returns: dict: A dictionary of certificates found in the store """ ret = dict() blacklist_keys = ["DnsNameList", "Thumbprint"] ps_cmd = [ "Get-ChildItem", "-Path", r"'Cert:\LocalMachine\{}'".format(certificate_store), "|", "Select-Object DnsNameList, SerialNumber, Subject, Thumbprint, Version", ] cmd_ret = _srvmgr(cmd=ps_cmd, return_json=True) try: items = salt.utils.json.loads(cmd_ret["stdout"], strict=False) except ValueError: raise CommandExecutionError("Unable to parse return data as Json.") for item in items: cert_info = dict() for key in item: if key not in blacklist_keys: cert_info[key.lower()] = item[key] cert_info["dnsnames"] = [] if item["DnsNameList"]: cert_info["dnsnames"] = [name["Unicode"] for name in item["DnsNameList"]] ret[item["Thumbprint"]] = cert_info return ret def _iisVersion(): pscmd = [] pscmd.append(r"Get-ItemProperty HKLM:\\SOFTWARE\\Microsoft\\InetStp\\") pscmd.append(" | Select-Object MajorVersion, MinorVersion") cmd_ret = _srvmgr(pscmd, return_json=True) try: items = salt.utils.json.loads(cmd_ret["stdout"], strict=False) except ValueError: log.error("Unable to parse return data as Json.") return -1 return decimal.Decimal( "{}.{}".format(items[0]["MajorVersion"], items[0]["MinorVersion"]) ) def _srvmgr(cmd, return_json=False): """ Execute a powershell command from the WebAdministration PS module. Args: cmd (list): The command to execute in a list return_json (bool): True formats the return in JSON, False just returns the output of the command. Returns: str: The output from the command """ if isinstance(cmd, list): cmd = " ".join(cmd) if return_json: cmd = "ConvertTo-Json -Compress -Depth 4 -InputObject @({})".format(cmd) cmd = "Import-Module WebAdministration; {}".format(cmd) ret = __salt__["cmd.run_all"](cmd, shell="powershell", python_shell=True) if ret["retcode"] != 0: log.error("Unable to execute command: %s\nError: %s", cmd, ret["stderr"]) return ret def _collection_match_to_index(pspath, colfilter, name, match): """ Returns index of collection item matching the match dictionary. """ collection = get_webconfiguration_settings( pspath, [{"name": name, "filter": colfilter}] )[0]["value"] for idx, collect_dict in enumerate(collection): if all(item in collect_dict.items() for item in match.items()): return idx return -1 def _prepare_settings(pspath, settings): """ Prepare settings before execution with get or set functions. Removes settings with a match parameter when index is not found. """ prepared_settings = [] for setting in settings: if setting.get("name", None) is None: log.warning("win_iis: Setting has no name: %s", setting) continue if setting.get("filter", None) is None: log.warning("win_iis: Setting has no filter: %s", setting) continue match = re.search(r"Collection\[(\{.*\})\]", setting["name"]) if match: name = setting["name"][: match.start(1) - 1] match_dict = yaml.load(match.group(1)) index = _collection_match_to_index( pspath, setting["filter"], name, match_dict ) if index == -1: log.warning("win_iis: No match found for setting: %s", setting) else: setting["name"] = setting["name"].replace(match.group(1), str(index)) prepared_settings.append(setting) else: prepared_settings.append(setting) return prepared_settings def list_sites(): """ List all the currently deployed websites. Returns: dict: A dictionary of the IIS sites and their properties. CLI Example: .. code-block:: bash salt '*' win_iis.list_sites """ ret = dict() ps_cmd = [ "Get-ChildItem", "-Path", r"'IIS:\Sites'", "|", "Select-Object applicationPool, Bindings, ID, Name, PhysicalPath, State", ] keep_keys = ("certificateHash", "certificateStoreName", "protocol", "sslFlags") cmd_ret = _srvmgr(cmd=ps_cmd, return_json=True) try: items = salt.utils.json.loads(cmd_ret["stdout"], strict=False) except ValueError: raise CommandExecutionError("Unable to parse return data as Json.") for item in items: bindings = dict() for binding in item["bindings"]["Collection"]: # Ignore bindings which do not have host names if binding["protocol"] not in ["http", "https"]: continue filtered_binding = dict() for key in binding: if key in keep_keys: filtered_binding.update({key.lower(): binding[key]}) binding_info = binding["bindingInformation"].split(":", 2) ipaddress, port, hostheader = [element.strip() for element in binding_info] filtered_binding.update( {"hostheader": hostheader, "ipaddress": ipaddress, "port": port} ) bindings[binding["bindingInformation"]] = filtered_binding ret[item["name"]] = { "apppool": item["applicationPool"], "bindings": bindings, "id": item["id"], "state": item["state"], "sourcepath": item["physicalPath"], } if not ret: log.warning("No sites found in output: %s", cmd_ret["stdout"]) return ret def create_site( name, sourcepath, apppool="", hostheader="", ipaddress="*", port=80, protocol="http" ): """ Create a basic website in IIS. .. note:: This function only validates against the site name, and will return True even if the site already exists with a different configuration. It will not modify the configuration of an existing site. Args: name (str): The IIS site name. sourcepath (str): The physical path of the IIS site. apppool (str): The name of the IIS application pool. hostheader (str): The host header of the binding. Usually the hostname or website name, ie: www.contoso.com ipaddress (str): The IP address of the binding. port (int): The TCP port of the binding. protocol (str): The application protocol of the binding. (http, https, etc.) Returns: bool: True if successful, otherwise False. .. note:: If an application pool is specified, and that application pool does not already exist, it will be created. CLI Example: .. code-block:: bash salt '*' win_iis.create_site name='My Test Site' sourcepath='c:\\stage' apppool='TestPool' """ protocol = str(protocol).lower() site_path = r"IIS:\Sites\{}".format(name) binding_info = _get_binding_info(hostheader, ipaddress, port) current_sites = list_sites() if name in current_sites: log.debug("Site '%s' already present.", name) return True if protocol not in _VALID_PROTOCOLS: message = "Invalid protocol '{}' specified. Valid formats: {}".format( protocol, _VALID_PROTOCOLS ) raise SaltInvocationError(message) ps_cmd = [ "New-Item", "-Path", r"'{}'".format(site_path), "-PhysicalPath", r"'{}'".format(sourcepath), "-Bindings", "@{{ protocol='{0}'; bindingInformation='{1}' }};".format( protocol, binding_info ), ] if apppool: if apppool in list_apppools(): log.debug("Utilizing pre-existing application pool: %s", apppool) else: log.debug("Application pool will be created: %s", apppool) create_apppool(apppool) ps_cmd.extend( [ "Set-ItemProperty", "-Path", "'{}'".format(site_path), "-Name", "ApplicationPool", "-Value", "'{}'".format(apppool), ] ) cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to create site: {}\nError: {}".format(name, cmd_ret["stderr"]) raise CommandExecutionError(msg) log.debug("Site created successfully: %s", name) return True def modify_site(name, sourcepath=None, apppool=None): """ Modify a basic website in IIS. .. versionadded:: 2017.7.0 Args: name (str): The IIS site name. sourcepath (str): The physical path of the IIS site. apppool (str): The name of the IIS application pool. Returns: bool: True if successful, otherwise False. .. note:: If an application pool is specified, and that application pool does not already exist, it will be created. CLI Example: .. code-block:: bash salt '*' win_iis.modify_site name='My Test Site' sourcepath='c:\\new_path' apppool='NewTestPool' """ site_path = r"IIS:\Sites\{}".format(name) current_sites = list_sites() if name not in current_sites: log.debug("Site '%s' not defined.", name) return False ps_cmd = list() if sourcepath: ps_cmd.extend( [ "Set-ItemProperty", "-Path", r"'{}'".format(site_path), "-Name", "PhysicalPath", "-Value", r"'{}'".format(sourcepath), ] ) if apppool: if apppool in list_apppools(): log.debug("Utilizing pre-existing application pool: %s", apppool) else: log.debug("Application pool will be created: %s", apppool) create_apppool(apppool) # If ps_cmd isn't empty, we need to add a semi-colon to run two commands if ps_cmd: ps_cmd.append(";") ps_cmd.extend( [ "Set-ItemProperty", "-Path", r"'{}'".format(site_path), "-Name", "ApplicationPool", "-Value", r"'{}'".format(apppool), ] ) cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to modify site: {}\nError: {}".format(name, cmd_ret["stderr"]) raise CommandExecutionError(msg) log.debug("Site modified successfully: %s", name) return True def remove_site(name): """ Delete a website from IIS. Args: name (str): The IIS site name. Returns: bool: True if successful, otherwise False .. note:: This will not remove the application pool used by the site. CLI Example: .. code-block:: bash salt '*' win_iis.remove_site name='My Test Site' """ current_sites = list_sites() if name not in current_sites: log.debug("Site already absent: %s", name) return True ps_cmd = ["Remove-WebSite", "-Name", r"'{}'".format(name)] cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to remove site: {}\nError: {}".format(name, cmd_ret["stderr"]) raise CommandExecutionError(msg) log.debug("Site removed successfully: %s", name) return True def stop_site(name): """ Stop a Web Site in IIS. .. versionadded:: 2017.7.0 Args: name (str): The name of the website to stop. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.stop_site name='My Test Site' """ ps_cmd = ["Stop-WebSite", r"'{}'".format(name)] cmd_ret = _srvmgr(ps_cmd) return cmd_ret["retcode"] == 0 def start_site(name): """ Start a Web Site in IIS. .. versionadded:: 2017.7.0 Args: name (str): The name of the website to start. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.start_site name='My Test Site' """ ps_cmd = ["Start-WebSite", r"'{}'".format(name)] cmd_ret = _srvmgr(ps_cmd) return cmd_ret["retcode"] == 0 def restart_site(name): """ Restart a Web Site in IIS. .. versionadded:: 2017.7.0 Args: name (str): The name of the website to restart. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.restart_site name='My Test Site' """ return stop_site(name) and start_site(name) def list_bindings(site): """ Get all configured IIS bindings for the specified site. Args: site (str): The name if the IIS Site Returns: dict: A dictionary of the binding names and properties. CLI Example: .. code-block:: bash salt '*' win_iis.list_bindings site """ ret = dict() sites = list_sites() if site not in sites: log.warning("Site not found: %s", site) return ret ret = sites[site]["bindings"] if not ret: log.warning("No bindings found for site: %s", site) return ret def create_binding( site, hostheader="", ipaddress="*", port=80, protocol="http", sslflags=None ): """ Create an IIS Web Binding. .. note:: This function only validates against the binding ipaddress:port:hostheader combination, and will return True even if the binding already exists with a different configuration. It will not modify the configuration of an existing binding. Args: site (str): The IIS site name. hostheader (str): The host header of the binding. Usually a hostname. ipaddress (str): The IP address of the binding. port (int): The TCP port of the binding. protocol (str): The application protocol of the binding. sslflags (str): The flags representing certificate type and storage of the binding. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.create_binding site='site0' hostheader='example.com' ipaddress='*' port='80' """ protocol = str(protocol).lower() name = _get_binding_info(hostheader, ipaddress, port) if protocol not in _VALID_PROTOCOLS: message = "Invalid protocol '{}' specified. Valid formats: {}".format( protocol, _VALID_PROTOCOLS ) raise SaltInvocationError(message) if sslflags: sslflags = int(sslflags) if sslflags not in _VALID_SSL_FLAGS: raise SaltInvocationError( "Invalid sslflags '{}' specified. Valid sslflags range: {}..{}".format( sslflags, _VALID_SSL_FLAGS[0], _VALID_SSL_FLAGS[-1] ) ) current_bindings = list_bindings(site) if name in current_bindings: log.debug("Binding already present: %s", name) return True if sslflags: ps_cmd = [ "New-WebBinding", "-Name", "'{}'".format(site), "-HostHeader", "'{}'".format(hostheader), "-IpAddress", "'{}'".format(ipaddress), "-Port", "'{}'".format(port), "-Protocol", "'{}'".format(protocol), "-SslFlags", "{}".format(sslflags), ] else: ps_cmd = [ "New-WebBinding", "-Name", "'{}'".format(site), "-HostHeader", "'{}'".format(hostheader), "-IpAddress", "'{}'".format(ipaddress), "-Port", "'{}'".format(port), "-Protocol", "'{}'".format(protocol), ] cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to create binding: {}\nError: {}".format(site, cmd_ret["stderr"]) raise CommandExecutionError(msg) if name in list_bindings(site): log.debug("Binding created successfully: %s", site) return True log.error("Unable to create binding: %s", site) return False def modify_binding( site, binding, hostheader=None, ipaddress=None, port=None, sslflags=None ): """ Modify an IIS Web Binding. Use ``site`` and ``binding`` to target the binding. .. versionadded:: 2017.7.0 Args: site (str): The IIS site name. binding (str): The binding to edit. This is a combination of the IP address, port, and hostheader. It is in the following format: ipaddress:port:hostheader. For example, ``*:80:`` or ``*:80:salt.com`` hostheader (str): The host header of the binding. Usually the hostname. ipaddress (str): The IP address of the binding. port (int): The TCP port of the binding. sslflags (str): The flags representing certificate type and storage of the binding. Returns: bool: True if successful, otherwise False CLI Example: The following will seat the host header of binding ``*:80:`` for ``site0`` to ``example.com`` .. code-block:: bash salt '*' win_iis.modify_binding site='site0' binding='*:80:' hostheader='example.com' """ if sslflags is not None and sslflags not in _VALID_SSL_FLAGS: raise SaltInvocationError( "Invalid sslflags '{}' specified. Valid sslflags range: {}..{}".format( sslflags, _VALID_SSL_FLAGS[0], _VALID_SSL_FLAGS[-1] ) ) current_sites = list_sites() if site not in current_sites: log.debug("Site '%s' not defined.", site) return False current_bindings = list_bindings(site) if binding not in current_bindings: log.debug("Binding '%s' not defined.", binding) return False # Split out the binding so we can insert new ones # Use the existing value if not passed i, p, h = binding.split(":") new_binding = ":".join( [ ipaddress if ipaddress is not None else i, str(port) if port is not None else str(p), hostheader if hostheader is not None else h, ] ) if new_binding != binding: ps_cmd = [ "Set-WebBinding", "-Name", "'{}'".format(site), "-BindingInformation", "'{}'".format(binding), "-PropertyName", "BindingInformation", "-Value", "'{}'".format(new_binding), ] cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to modify binding: {}\nError: {}".format( binding, cmd_ret["stderr"] ) raise CommandExecutionError(msg) if ( sslflags is not None and sslflags != current_sites[site]["bindings"][binding]["sslflags"] ): ps_cmd = [ "Set-WebBinding", "-Name", "'{}'".format(site), "-BindingInformation", "'{}'".format(new_binding), "-PropertyName", "sslflags", "-Value", "'{}'".format(sslflags), ] cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to modify binding SSL Flags: {}\nError: {}".format( sslflags, cmd_ret["stderr"] ) raise CommandExecutionError(msg) log.debug("Binding modified successfully: %s", binding) return True def remove_binding(site, hostheader="", ipaddress="*", port=80): """ Remove an IIS binding. Args: site (str): The IIS site name. hostheader (str): The host header of the binding. ipaddress (str): The IP address of the binding. port (int): The TCP port of the binding. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.remove_binding site='site0' hostheader='example.com' ipaddress='*' port='80' """ name = _get_binding_info(hostheader, ipaddress, port) current_bindings = list_bindings(site) if name not in current_bindings: log.debug("Binding already absent: %s", name) return True ps_cmd = [ "Remove-WebBinding", "-HostHeader", "'{}'".format(hostheader), "-IpAddress", "'{}'".format(ipaddress), "-Port", "'{}'".format(port), ] cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to remove binding: {}\nError: {}".format(site, cmd_ret["stderr"]) raise CommandExecutionError(msg) if name not in list_bindings(site): log.debug("Binding removed successfully: %s", site) return True log.error("Unable to remove binding: %s", site) return False def list_cert_bindings(site): """ List certificate bindings for an IIS site. .. versionadded:: 2016.11.0 Args: site (str): The IIS site name. Returns: dict: A dictionary of the binding names and properties. CLI Example: .. code-block:: bash salt '*' win_iis.list_bindings site """ ret = dict() sites = list_sites() if site not in sites: log.warning("Site not found: %s", site) return ret for binding in sites[site]["bindings"]: if sites[site]["bindings"][binding]["certificatehash"]: ret[binding] = sites[site]["bindings"][binding] if not ret: log.warning("No certificate bindings found for site: %s", site) return ret def create_cert_binding(name, site, hostheader="", ipaddress="*", port=443, sslflags=0): """ Assign a certificate to an IIS Web Binding. .. versionadded:: 2016.11.0 .. note:: The web binding that the certificate is being assigned to must already exist. Args: name (str): The thumbprint of the certificate. site (str): The IIS site name. hostheader (str): The host header of the binding. ipaddress (str): The IP address of the binding. port (int): The TCP port of the binding. sslflags (int): Flags representing certificate type and certificate storage of the binding. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.create_cert_binding name='AAA000' site='site0' hostheader='example.com' ipaddress='*' port='443' """ name = str(name).upper() binding_info = _get_binding_info(hostheader, ipaddress, port) if _iisVersion() < 8: # IIS 7.5 and earlier don't support SNI for HTTPS, therefore cert bindings don't contain the host header binding_info = binding_info.rpartition(":")[0] + ":" binding_path = r"IIS:\SslBindings\{}".format(binding_info.replace(":", "!")) if sslflags not in _VALID_SSL_FLAGS: raise SaltInvocationError( "Invalid sslflags '{}' specified. Valid sslflags range: {}..{}".format( sslflags, _VALID_SSL_FLAGS[0], _VALID_SSL_FLAGS[-1] ) ) # Verify that the target binding exists. current_bindings = list_bindings(site) if binding_info not in current_bindings: log.error("Binding not present: %s", binding_info) return False # Check to see if the certificate is already assigned. current_name = None for current_binding in current_bindings: if binding_info == current_binding: current_name = current_bindings[current_binding]["certificatehash"] log.debug("Current certificate thumbprint: %s", current_name) log.debug("New certificate thumbprint: %s", name) if name == current_name: log.debug("Certificate already present for binding: %s", name) return True # Verify that the certificate exists. certs = _list_certs() if name not in certs: log.error("Certificate not present: %s", name) return False if _iisVersion() < 8: # IIS 7.5 and earlier have different syntax for associating a certificate with a site # Modify IP spec to IIS 7.5 format iis7path = binding_path.replace(r"\*!", "\\0.0.0.0!") # win 2008 uses the following format: ip!port and not ip!port! if iis7path.endswith("!"): iis7path = iis7path[:-1] ps_cmd = [ "New-Item", "-Path", "'{}'".format(iis7path), "-Thumbprint", "'{}'".format(name), ] else: ps_cmd = [ "New-Item", "-Path", "'{}'".format(binding_path), "-Thumbprint", "'{}'".format(name), "-SSLFlags", "{}".format(sslflags), ] cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to create certificate binding: {}\nError: {}".format( name, cmd_ret["stderr"] ) raise CommandExecutionError(msg) new_cert_bindings = list_cert_bindings(site) if binding_info not in new_cert_bindings: log.error("Binding not present: %s", binding_info) return False if name == new_cert_bindings[binding_info]["certificatehash"]: log.debug("Certificate binding created successfully: %s", name) return True log.error("Unable to create certificate binding: %s", name) return False def remove_cert_binding(name, site, hostheader="", ipaddress="*", port=443): """ Remove a certificate from an IIS Web Binding. .. versionadded:: 2016.11.0 .. note:: This function only removes the certificate from the web binding. It does not remove the web binding itself. Args: name (str): The thumbprint of the certificate. site (str): The IIS site name. hostheader (str): The host header of the binding. ipaddress (str): The IP address of the binding. port (int): The TCP port of the binding. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.remove_cert_binding name='AAA000' site='site0' hostheader='example.com' ipaddress='*' port='443' """ name = str(name).upper() binding_info = _get_binding_info(hostheader, ipaddress, port) # Child items of IIS:\SslBindings do not return populated host header info # in all circumstances, so it's necessary to use IIS:\Sites instead. ps_cmd = [ "$Site = Get-ChildItem", "-Path", r"'IIS:\Sites'", "|", "Where-Object", r" {{ $_.Name -Eq '{0}' }};".format(site), "$Binding = $Site.Bindings.Collection", r"| Where-Object { $_.bindingInformation", r"-Eq '{0}' }};".format(binding_info), "$Binding.RemoveSslCertificate()", ] # Verify that the binding exists for the site, and that the target # certificate is assigned to the binding. current_cert_bindings = list_cert_bindings(site) if binding_info not in current_cert_bindings: log.warning("Binding not found: %s", binding_info) return True if name != current_cert_bindings[binding_info]["certificatehash"]: log.debug("Certificate binding already absent: %s", name) return True cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to remove certificate binding: {}\nError: {}".format( name, cmd_ret["stderr"] ) raise CommandExecutionError(msg) new_cert_bindings = list_cert_bindings(site) if binding_info not in new_cert_bindings: log.warning("Binding not found: %s", binding_info) return True if name != new_cert_bindings[binding_info]["certificatehash"]: log.debug("Certificate binding removed successfully: %s", name) return True log.error("Unable to remove certificate binding: %s", name) return False def list_apppools(): """ List all configured IIS application pools. Returns: dict: A dictionary of IIS application pools and their details. CLI Example: .. code-block:: bash salt '*' win_iis.list_apppools """ ret = dict() ps_cmd = [] ps_cmd.append(r"Get-ChildItem -Path 'IIS:\AppPools' | Select-Object Name, State") # Include the equivalent of output from the Applications column, since this # isn't a normal property, we have to populate it via filtered output from # the Get-WebConfigurationProperty cmdlet. ps_cmd.append(r", @{ Name = 'Applications'; Expression = { $AppPool = $_.Name;") ps_cmd.append("$AppPath = 'machine/webroot/apphost';") ps_cmd.append("$FilterBase = '/system.applicationHost/sites/site/application';") ps_cmd.append("$FilterBase += \"[@applicationPool = '$($AppPool)' and @path\";") ps_cmd.append("$FilterRoot = \"$($FilterBase) = '/']/parent::*\";") ps_cmd.append("$FilterNonRoot = \"$($FilterBase) != '/']\";") ps_cmd.append( "Get-WebConfigurationProperty -Filter $FilterRoot -PsPath $AppPath -Name Name" ) ps_cmd.append(r"| ForEach-Object { $_.Value };") ps_cmd.append( "Get-WebConfigurationProperty -Filter $FilterNonRoot -PsPath $AppPath -Name" " Path" ) ps_cmd.append(r"| ForEach-Object { $_.Value } | Where-Object { $_ -ne '/' }") ps_cmd.append("} }") cmd_ret = _srvmgr(cmd=ps_cmd, return_json=True) try: items = salt.utils.json.loads(cmd_ret["stdout"], strict=False) except ValueError: raise CommandExecutionError("Unable to parse return data as Json.") for item in items: applications = list() # If there are no associated apps, Applications will be an empty dict, # if there is one app, it will be a string, and if there are multiple, # it will be a dict with 'Count' and 'value' as the keys. if isinstance(item["Applications"], dict): if "value" in item["Applications"]: applications += item["Applications"]["value"] else: applications.append(item["Applications"]) ret[item["name"]] = {"state": item["state"], "applications": applications} if not ret: log.warning("No application pools found in output: %s", cmd_ret["stdout"]) return ret def create_apppool(name): """ Create an IIS application pool. .. note:: This function only validates against the application pool name, and will return True even if the application pool already exists with a different configuration. It will not modify the configuration of an existing application pool. Args: name (str): The name of the IIS application pool. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.create_apppool name='MyTestPool' """ current_apppools = list_apppools() apppool_path = r"IIS:\AppPools\{}".format(name) if name in current_apppools: log.debug("Application pool '%s' already present.", name) return True ps_cmd = ["New-Item", "-Path", r"'{}'".format(apppool_path)] cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to create application pool: {}\nError: {}".format( name, cmd_ret["stderr"] ) raise CommandExecutionError(msg) log.debug("Application pool created successfully: %s", name) return True def remove_apppool(name): """ Remove an IIS application pool. Args: name (str): The name of the IIS application pool. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.remove_apppool name='MyTestPool' """ current_apppools = list_apppools() apppool_path = r"IIS:\AppPools\{}".format(name) if name not in current_apppools: log.debug("Application pool already absent: %s", name) return True ps_cmd = ["Remove-Item", "-Path", r"'{}'".format(apppool_path), "-Recurse"] cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to remove application pool: {}\nError: {}".format( name, cmd_ret["stderr"] ) raise CommandExecutionError(msg) log.debug("Application pool removed successfully: %s", name) return True def stop_apppool(name): """ Stop an IIS application pool. .. versionadded:: 2017.7.0 Args: name (str): The name of the App Pool to stop. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.stop_apppool name='MyTestPool' """ ps_cmd = ["Stop-WebAppPool", r"'{}'".format(name)] cmd_ret = _srvmgr(ps_cmd) return cmd_ret["retcode"] == 0 def start_apppool(name): """ Start an IIS application pool. .. versionadded:: 2017.7.0 Args: name (str): The name of the App Pool to start. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.start_apppool name='MyTestPool' """ ps_cmd = ["Start-WebAppPool", r"'{}'".format(name)] cmd_ret = _srvmgr(ps_cmd) return cmd_ret["retcode"] == 0 def restart_apppool(name): """ Restart an IIS application pool. .. versionadded:: 2016.11.0 Args: name (str): The name of the IIS application pool. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.restart_apppool name='MyTestPool' """ ps_cmd = ["Restart-WebAppPool", r"'{}'".format(name)] cmd_ret = _srvmgr(ps_cmd) return cmd_ret["retcode"] == 0 def get_container_setting(name, container, settings): """ Get the value of the setting for the IIS container. .. versionadded:: 2016.11.0 Args: name (str): The name of the IIS container. container (str): The type of IIS container. The container types are: AppPools, Sites, SslBindings settings (dict): A dictionary of the setting names and their values. Returns: dict: A dictionary of the provided settings and their values. CLI Example: .. code-block:: bash salt '*' win_iis.get_container_setting name='MyTestPool' container='AppPools' settings="['processModel.identityType']" """ ret = dict() ps_cmd = list() ps_cmd_validate = list() container_path = r"IIS:\{}\{}".format(container, name) if not settings: log.warning("No settings provided") return ret ps_cmd.append(r"$Settings = @{};") for setting in settings: # Build the commands to verify that the property names are valid. ps_cmd_validate.extend( [ "Get-ItemProperty", "-Path", "'{}'".format(container_path), "-Name", "'{}'".format(setting), "-ErrorAction", "Stop", "|", "Out-Null;", ] ) # Some ItemProperties are Strings and others are ConfigurationAttributes. # Since the former doesn't have a Value property, we need to account # for this. ps_cmd.append("$Property = Get-ItemProperty -Path '{}'".format(container_path)) ps_cmd.append("-Name '{}' -ErrorAction Stop;".format(setting)) ps_cmd.append(r"if (([String]::IsNullOrEmpty($Property) -eq $False) -and") ps_cmd.append(r"($Property.GetType()).Name -eq 'ConfigurationAttribute') {") ps_cmd.append(r"$Property = $Property | Select-Object") ps_cmd.append(r"-ExpandProperty Value };") ps_cmd.append("$Settings['{}'] = [String] $Property;".format(setting)) ps_cmd.append(r"$Property = $Null;") # Validate the setting names that were passed in. cmd_ret = _srvmgr(cmd=ps_cmd_validate, return_json=True) if cmd_ret["retcode"] != 0: message = ( "One or more invalid property names were specified for the provided" " container." ) raise SaltInvocationError(message) ps_cmd.append("$Settings") cmd_ret = _srvmgr(cmd=ps_cmd, return_json=True) try: items = salt.utils.json.loads(cmd_ret["stdout"], strict=False) if isinstance(items, list): ret.update(items[0]) else: ret.update(items) except ValueError: raise CommandExecutionError("Unable to parse return data as Json.") return ret def set_container_setting(name, container, settings): """ Set the value of the setting for an IIS container. .. versionadded:: 2016.11.0 Args: name (str): The name of the IIS container. container (str): The type of IIS container. The container types are: AppPools, Sites, SslBindings settings (dict): A dictionary of the setting names and their values. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.set_container_setting name='MyTestPool' container='AppPools' settings="{'managedPipeLineMode': 'Integrated'}" """ identityType_map2string = { "0": "LocalSystem", "1": "LocalService", "2": "NetworkService", "3": "SpecificUser", "4": "ApplicationPoolIdentity", } identityType_map2numeric = { "LocalSystem": "0", "LocalService": "1", "NetworkService": "2", "SpecificUser": "3", "ApplicationPoolIdentity": "4", } ps_cmd = list() container_path = r"IIS:\{}\{}".format(container, name) if not settings: log.warning("No settings provided") return False # Treat all values as strings for the purpose of comparing them to existing values. for setting in settings: settings[setting] = str(settings[setting]) current_settings = get_container_setting( name=name, container=container, settings=settings.keys() ) if settings == current_settings: log.debug("Settings already contain the provided values.") return True for setting in settings: # If the value is numeric, don't treat it as a string in PowerShell. try: complex(settings[setting]) value = settings[setting] except ValueError: value = "'{}'".format(settings[setting]) # Map to numeric to support server 2008 if ( setting == "processModel.identityType" and settings[setting] in identityType_map2numeric.keys() ): value = identityType_map2numeric[settings[setting]] ps_cmd.extend( [ "Set-ItemProperty", "-Path", "'{}'".format(container_path), "-Name", "'{}'".format(setting), "-Value", "{};".format(value), ] ) cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to set settings for {}: {}".format(container, name) raise CommandExecutionError(msg) # Get the fields post-change so that we can verify tht all values # were modified successfully. Track the ones that weren't. new_settings = get_container_setting( name=name, container=container, settings=settings.keys() ) failed_settings = dict() for setting in settings: # map identity type from numeric to string for comparing if ( setting == "processModel.identityType" and settings[setting] in identityType_map2string.keys() ): settings[setting] = identityType_map2string[settings[setting]] if str(settings[setting]) != str(new_settings[setting]): failed_settings[setting] = settings[setting] if failed_settings: log.error("Failed to change settings: %s", failed_settings) return False log.debug("Settings configured successfully: %s", settings.keys()) return True def list_apps(site): """ Get all configured IIS applications for the specified site. Args: site (str): The IIS site name. Returns: A dictionary of the application names and properties. CLI Example: .. code-block:: bash salt '*' win_iis.list_apps site """ ret = dict() ps_cmd = list() ps_cmd.append("Get-WebApplication -Site '{}'".format(site)) ps_cmd.append( r"| Select-Object applicationPool, path, PhysicalPath, preloadEnabled," ) ps_cmd.append(r"@{ Name='name'; Expression={ $_.path.Split('/', 2)[-1] } },") ps_cmd.append( r"@{ Name='protocols'; Expression={ @( $_.enabledProtocols.Split(',')" ) ps_cmd.append(r"| Foreach-Object { $_.Trim() } ) } }") cmd_ret = _srvmgr(cmd=ps_cmd, return_json=True) try: items = salt.utils.json.loads(cmd_ret["stdout"], strict=False) except ValueError: raise CommandExecutionError("Unable to parse return data as Json.") for item in items: protocols = list() # If there are no associated protocols, protocols will be an empty dict, # if there is one protocol, it will be a string, and if there are # multiple, it will be a dict with 'Count' and 'value' as the keys. if isinstance(item["protocols"], dict): if "value" in item["protocols"]: protocols += item["protocols"]["value"] else: protocols.append(item["protocols"]) ret[item["name"]] = { "apppool": item["applicationPool"], "path": item["path"], "preload": item["preloadEnabled"], "protocols": protocols, "sourcepath": item["PhysicalPath"], } if not ret: log.warning("No apps found in output: %s", cmd_ret) return ret def create_app(name, site, sourcepath, apppool=None): """ Create an IIS application. .. note:: This function only validates against the application name, and will return True even if the application already exists with a different configuration. It will not modify the configuration of an existing application. Args: name (str): The IIS application. site (str): The IIS site name. sourcepath (str): The physical path. apppool (str): The name of the IIS application pool. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.create_app name='app0' site='site0' sourcepath='C:\\site0' apppool='site0' """ current_apps = list_apps(site) if name in current_apps: log.debug("Application already present: %s", name) return True # The target physical path must exist. if not os.path.isdir(sourcepath): log.error("Path is not present: %s", sourcepath) return False ps_cmd = [ "New-WebApplication", "-Name", "'{}'".format(name), "-Site", "'{}'".format(site), "-PhysicalPath", "'{}'".format(sourcepath), ] if apppool: ps_cmd.extend(["-ApplicationPool", "'{}'".format(apppool)]) cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to create application: {}\nError: {}".format( name, cmd_ret["stderr"] ) raise CommandExecutionError(msg) new_apps = list_apps(site) if name in new_apps: log.debug("Application created successfully: %s", name) return True log.error("Unable to create application: %s", name) return False def remove_app(name, site): """ Remove an IIS application. Args: name (str): The application name. site (str): The IIS site name. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.remove_app name='app0' site='site0' """ current_apps = list_apps(site) if name not in current_apps: log.debug("Application already absent: %s", name) return True ps_cmd = [ "Remove-WebApplication", "-Name", "'{}'".format(name), "-Site", "'{}'".format(site), ] cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to remove application: {}\nError: {}".format( name, cmd_ret["stderr"] ) raise CommandExecutionError(msg) new_apps = list_apps(site) if name not in new_apps: log.debug("Application removed successfully: %s", name) return True log.error("Unable to remove application: %s", name) return False def list_vdirs(site, app=_DEFAULT_APP): """ Get all configured IIS virtual directories for the specified site, or for the combination of site and application. Args: site (str): The IIS site name. app (str): The IIS application. Returns: dict: A dictionary of the virtual directory names and properties. CLI Example: .. code-block:: bash salt '*' win_iis.list_vdirs site """ ret = dict() ps_cmd = [ "Get-WebVirtualDirectory", "-Site", r"'{}'".format(site), "-Application", r"'{}'".format(app), "|", "Select-Object PhysicalPath, @{ Name = 'name';", r"Expression = { $_.path.Trim('/') } }", ] cmd_ret = _srvmgr(cmd=ps_cmd, return_json=True) try: items = salt.utils.json.loads(cmd_ret["stdout"], strict=False) except ValueError: raise CommandExecutionError("Unable to parse return data as Json.") for item in items: ret[item["name"]] = {"sourcepath": item["physicalPath"]} if not ret: log.warning("No vdirs found in output: %s", cmd_ret) return ret def create_vdir(name, site, sourcepath, app=_DEFAULT_APP): """ Create an IIS virtual directory. .. note:: This function only validates against the virtual directory name, and will return True even if the virtual directory already exists with a different configuration. It will not modify the configuration of an existing virtual directory. Args: name (str): The virtual directory name. site (str): The IIS site name. sourcepath (str): The physical path. app (str): The IIS application. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.create_vdir name='vd0' site='site0' sourcepath='C:\\inetpub\\vdirs\\vd0' """ current_vdirs = list_vdirs(site, app) if name in current_vdirs: log.debug("Virtual directory already present: %s", name) return True # The target physical path must exist. if not os.path.isdir(sourcepath): log.error("Path is not present: %s", sourcepath) return False ps_cmd = [ "New-WebVirtualDirectory", "-Name", r"'{}'".format(name), "-Site", r"'{}'".format(site), "-PhysicalPath", r"'{}'".format(sourcepath), ] if app != _DEFAULT_APP: ps_cmd.extend(["-Application", r"'{}'".format(app)]) cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to create virtual directory: {}\nError: {}".format( name, cmd_ret["stderr"] ) raise CommandExecutionError(msg) new_vdirs = list_vdirs(site, app) if name in new_vdirs: log.debug("Virtual directory created successfully: %s", name) return True log.error("Unable to create virtual directory: %s", name) return False def remove_vdir(name, site, app=_DEFAULT_APP): """ Remove an IIS virtual directory. Args: name (str): The virtual directory name. site (str): The IIS site name. app (str): The IIS application. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.remove_vdir name='vdir0' site='site0' """ current_vdirs = list_vdirs(site, app) app_path = os.path.join(*app.rstrip("/").split("/")) if app_path: app_path = "{}\\".format(app_path) vdir_path = r"IIS:\Sites\{}\{}{}".format(site, app_path, name) if name not in current_vdirs: log.debug("Virtual directory already absent: %s", name) return True # We use Remove-Item here instead of Remove-WebVirtualDirectory, since the # latter has a bug that causes it to always prompt for user input. ps_cmd = ["Remove-Item", "-Path", r"'{}'".format(vdir_path), "-Recurse"] cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to remove virtual directory: {}\nError: {}".format( name, cmd_ret["stderr"] ) raise CommandExecutionError(msg) new_vdirs = list_vdirs(site, app) if name not in new_vdirs: log.debug("Virtual directory removed successfully: %s", name) return True log.error("Unable to remove virtual directory: %s", name) return False def list_backups(): r""" List the IIS Configuration Backups on the System. .. versionadded:: 2017.7.0 .. note:: Backups are made when a configuration is edited. Manual backups are stored in the ``$env:Windir\System32\inetsrv\backup`` folder. Returns: dict: A dictionary of IIS Configurations backed up on the system. CLI Example: .. code-block:: bash salt '*' win_iis.list_backups """ ret = dict() ps_cmd = [ "Get-WebConfigurationBackup", "|", "Select Name, CreationDate,", '@{N="FormattedDate"; E={$_.CreationDate.ToString("G")}}', ] cmd_ret = _srvmgr(cmd=ps_cmd, return_json=True) try: items = salt.utils.json.loads(cmd_ret["stdout"], strict=False) except ValueError: raise CommandExecutionError("Unable to parse return data as Json.") for item in items: if item["FormattedDate"]: ret[item["Name"]] = item["FormattedDate"] else: ret[item["Name"]] = item["CreationDate"] if not ret: log.warning("No backups found in output: %s", cmd_ret) return ret def create_backup(name): r""" Backup an IIS Configuration on the System. .. versionadded:: 2017.7.0 .. note:: Backups are stored in the ``$env:Windir\System32\inetsrv\backup`` folder. Args: name (str): The name to give the backup Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.create_backup good_config_20170209 """ if name in list_backups(): raise CommandExecutionError("Backup already present: {}".format(name)) ps_cmd = ["Backup-WebConfiguration", "-Name", "'{}'".format(name)] cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to backup web configuration: {}\nError: {}".format( name, cmd_ret["stderr"] ) raise CommandExecutionError(msg) return name in list_backups() def remove_backup(name): """ Remove an IIS Configuration backup from the System. .. versionadded:: 2017.7.0 Args: name (str): The name of the backup to remove Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.remove_backup backup_20170209 """ if name not in list_backups(): log.debug("Backup already removed: %s", name) return True ps_cmd = ["Remove-WebConfigurationBackup", "-Name", "'{}'".format(name)] cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to remove web configuration: {}\nError: {}".format( name, cmd_ret["stderr"] ) raise CommandExecutionError(msg) return name not in list_backups() def list_worker_processes(apppool): """ Returns a list of worker processes that correspond to the passed application pool. .. versionadded:: 2017.7.0 Args: apppool (str): The application pool to query Returns: dict: A dictionary of worker processes with their process IDs CLI Example: .. code-block:: bash salt '*' win_iis.list_worker_processes 'My App Pool' """ ps_cmd = ["Get-ChildItem", r"'IIS:\AppPools\{}\WorkerProcesses'".format(apppool)] cmd_ret = _srvmgr(cmd=ps_cmd, return_json=True) try: items = salt.utils.json.loads(cmd_ret["stdout"], strict=False) except ValueError: raise CommandExecutionError("Unable to parse return data as Json.") ret = dict() for item in items: ret[item["processId"]] = item["appPoolName"] if not ret: log.warning("No backups found in output: %s", cmd_ret) return ret def get_webapp_settings(name, site, settings): r""" .. versionadded:: 2017.7.0 Get the value of the setting for the IIS web application. .. note:: Params are case sensitive :param str name: The name of the IIS web application. :param str site: The site name contains the web application. Example: Default Web Site :param str settings: A dictionary of the setting names and their values. Available settings: physicalPath, applicationPool, userName, password Returns: dict: A dictionary of the provided settings and their values. CLI Example: .. code-block:: bash salt '*' win_iis.get_webapp_settings name='app0' site='Default Web Site' settings="['physicalPath','applicationPool']" """ ret = dict() pscmd = list() availableSettings = ("physicalPath", "applicationPool", "userName", "password") if not settings: log.warning("No settings provided") return ret pscmd.append(r"$Settings = @{};") # Verify setting is ine predefined settings and append relevant query command per setting key for setting in settings: if setting in availableSettings: if setting == "userName" or setting == "password": pscmd.append( " $Property = Get-WebConfigurationProperty -Filter" " \"system.applicationHost/sites/site[@name='{}']/application[@path='/{}']/virtualDirectory[@path='/']\"".format( site, name ) ) pscmd.append( r' -Name "{}" -ErrorAction Stop | select Value;'.format(setting) ) pscmd.append( r" $Property = $Property | Select-Object -ExpandProperty Value;" ) pscmd.append(r" $Settings['{}'] = [String] $Property;".format(setting)) pscmd.append(r" $Property = $Null;") if setting == "physicalPath" or setting == "applicationPool": pscmd.append( r" $Property = (get-webapplication {}).{};".format(name, setting) ) pscmd.append(r" $Settings['{}'] = [String] $Property;".format(setting)) pscmd.append(r" $Property = $Null;") else: availSetStr = ", ".join(availableSettings) message = ( "Unexpected setting:" + setting + ". Available settings are: " + availSetStr ) raise SaltInvocationError(message) pscmd.append(" $Settings") # Run commands and return data as json cmd_ret = _srvmgr(cmd="".join(pscmd), return_json=True) # Update dict var to return data try: items = salt.utils.json.loads(cmd_ret["stdout"], strict=False) if isinstance(items, list): ret.update(items[0]) else: ret.update(items) except ValueError: log.error("Unable to parse return data as Json.") if None in ret.values(): message = ( "Some values are empty - please validate site and web application names." " Some commands are case sensitive" ) raise SaltInvocationError(message) return ret def set_webapp_settings(name, site, settings): r""" .. versionadded:: 2017.7.0 Configure an IIS application. .. note:: This function only configures an existing app. Params are case sensitive. :param str name: The IIS application. :param str site: The IIS site name. :param str settings: A dictionary of the setting names and their values. - physicalPath: The physical path of the webapp. - applicationPool: The application pool for the webapp. - userName: "connectAs" user - password: "connectAs" password for user :return: A boolean representing whether all changes succeeded. :rtype: bool CLI Example: .. code-block:: bash salt '*' win_iis.set_webapp_settings name='app0' site='site0' settings="{'physicalPath': 'C:\site0', 'apppool': 'site0'}" """ pscmd = list() current_apps = list_apps(site) current_sites = list_sites() availableSettings = ("physicalPath", "applicationPool", "userName", "password") # Validate params if name not in current_apps: msg = "Application" + name + "doesn't exist" raise SaltInvocationError(msg) if site not in current_sites: msg = "Site" + site + "doesn't exist" raise SaltInvocationError(msg) if not settings: msg = "No settings provided" raise SaltInvocationError(msg) # Treat all values as strings for the purpose of comparing them to existing values & validate settings exists in predefined settings list for setting in settings.keys(): if setting in availableSettings: settings[setting] = str(settings[setting]) else: availSetStr = ", ".join(availableSettings) log.error("Unexpected setting: %s ", setting) log.error("Available settings: %s", availSetStr) msg = "Unexpected setting:" + setting + " Available settings:" + availSetStr raise SaltInvocationError(msg) # Check if settings already configured current_settings = get_webapp_settings( name=name, site=site, settings=settings.keys() ) if settings == current_settings: log.warning("Settings already contain the provided values.") return True for setting in settings: # If the value is numeric, don't treat it as a string in PowerShell. try: complex(settings[setting]) value = settings[setting] except ValueError: value = "'{}'".format(settings[setting]) # Append relevant update command per setting key if setting == "userName" or setting == "password": pscmd.append( " Set-WebConfigurationProperty -Filter" " \"system.applicationHost/sites/site[@name='{}']/application[@path='/{}']/virtualDirectory[@path='/']\"".format( site, name ) ) pscmd.append(' -Name "{}" -Value {};'.format(setting, value)) if setting == "physicalPath" or setting == "applicationPool": pscmd.append( r' Set-ItemProperty "IIS:\Sites\{}\{}" -Name {} -Value {};'.format( site, name, setting, value ) ) if setting == "physicalPath": if not os.path.isdir(settings[setting]): msg = "Path is not present: " + settings[setting] raise SaltInvocationError(msg) # Run commands cmd_ret = _srvmgr(pscmd) # Verify commands completed successfully if cmd_ret["retcode"] != 0: msg = "Unable to set settings for web application {}".format(name) raise SaltInvocationError(msg) # verify changes new_settings = get_webapp_settings(name=name, site=site, settings=settings.keys()) failed_settings = dict() for setting in settings: if str(settings[setting]) != str(new_settings[setting]): failed_settings[setting] = settings[setting] if failed_settings: log.error("Failed to change settings: %s", failed_settings) return False log.debug("Settings configured successfully: %s", list(settings)) return True def get_webconfiguration_settings(name, settings): r""" Get the webconfiguration settings for the IIS PSPath. Args: name (str): The PSPath of the IIS webconfiguration settings. settings (list): A list of dictionaries containing setting name and filter. Returns: dict: A list of dictionaries containing setting name, filter and value. CLI Example: .. code-block:: bash salt '*' win_iis.get_webconfiguration_settings name='IIS:\' settings="[{'name': 'enabled', 'filter': 'system.webServer/security/authentication/anonymousAuthentication'}]" """ ret = {} ps_cmd = [r"$Settings = New-Object System.Collections.ArrayList;"] ps_cmd_validate = [] settings = _prepare_settings(name, settings) if not settings: log.warning("No settings provided") return ret for setting in settings: # Build the commands to verify that the property names are valid. ps_cmd_validate.extend( [ "Get-WebConfigurationProperty", "-PSPath", "'{}'".format(name), "-Filter", "'{}'".format(setting["filter"]), "-Name", "'{}'".format(setting["name"]), "-ErrorAction", "Stop", "|", "Out-Null;", ] ) # Some ItemProperties are Strings and others are ConfigurationAttributes. # Since the former doesn't have a Value property, we need to account # for this. ps_cmd.append( "$Property = Get-WebConfigurationProperty -PSPath '{}'".format(name) ) ps_cmd.append( "-Name '{}' -Filter '{}' -ErrorAction Stop;".format( setting["name"], setting["filter"] ) ) if setting["name"].split(".")[-1] == "Collection": if "value" in setting: ps_cmd.append( "$Property = $Property | select -Property {} ;".format( ",".join(list(setting["value"][0].keys())) ) ) ps_cmd.append( "$Settings.add(@{{filter='{0}';name='{1}';value=[System.Collections.ArrayList]" " @($Property)}})| Out-Null;".format(setting["filter"], setting["name"]) ) else: ps_cmd.append(r"if (([String]::IsNullOrEmpty($Property) -eq $False) -and") ps_cmd.append(r"($Property.GetType()).Name -eq 'ConfigurationAttribute') {") ps_cmd.append(r"$Property = $Property | Select-Object") ps_cmd.append(r"-ExpandProperty Value };") ps_cmd.append( "$Settings.add(@{{filter='{0}';name='{1}';value=[String] $Property}})|" " Out-Null;".format(setting["filter"], setting["name"]) ) ps_cmd.append(r"$Property = $Null;") # Validate the setting names that were passed in. cmd_ret = _srvmgr(cmd=ps_cmd_validate, return_json=True) if cmd_ret["retcode"] != 0: message = ( "One or more invalid property names were specified for the provided" " container." ) raise SaltInvocationError(message) ps_cmd.append("$Settings") cmd_ret = _srvmgr(cmd=ps_cmd, return_json=True) try: ret = salt.utils.json.loads(cmd_ret["stdout"], strict=False) except ValueError: raise CommandExecutionError("Unable to parse return data as Json.") return ret def set_webconfiguration_settings(name, settings): r""" Set the value of the setting for an IIS container. Args: name (str): The PSPath of the IIS webconfiguration settings. settings (list): A list of dictionaries containing setting name, filter and value. Returns: bool: True if successful, otherwise False CLI Example: .. code-block:: bash salt '*' win_iis.set_webconfiguration_settings name='IIS:\' settings="[{'name': 'enabled', 'filter': 'system.webServer/security/authentication/anonymousAuthentication', 'value': False}]" """ ps_cmd = [] settings = _prepare_settings(name, settings) if not settings: log.warning("No settings provided") return False # Treat all values as strings for the purpose of comparing them to existing values. for idx, setting in enumerate(settings): if setting["name"].split(".")[-1] != "Collection": settings[idx]["value"] = str(setting["value"]) current_settings = get_webconfiguration_settings(name=name, settings=settings) if settings == current_settings: log.debug("Settings already contain the provided values.") return True for setting in settings: # If the value is numeric, don't treat it as a string in PowerShell. if setting["name"].split(".")[-1] != "Collection": try: complex(setting["value"]) value = setting["value"] except ValueError: value = "'{}'".format(setting["value"]) else: configelement_list = [] for value_item in setting["value"]: configelement_construct = [] for key, value in value_item.items(): configelement_construct.append("{}='{}'".format(key, value)) configelement_list.append( "@{" + ";".join(configelement_construct) + "}" ) value = ",".join(configelement_list) ps_cmd.extend( [ "Set-WebConfigurationProperty", "-PSPath", "'{}'".format(name), "-Filter", "'{}'".format(setting["filter"]), "-Name", "'{}'".format(setting["name"]), "-Value", "{};".format(value), ] ) cmd_ret = _srvmgr(ps_cmd) if cmd_ret["retcode"] != 0: msg = "Unable to set settings for {}".format(name) raise CommandExecutionError(msg) # Get the fields post-change so that we can verify tht all values # were modified successfully. Track the ones that weren't. new_settings = get_webconfiguration_settings(name=name, settings=settings) failed_settings = [] for idx, setting in enumerate(settings): is_collection = setting["name"].split(".")[-1] == "Collection" if ( not is_collection and str(setting["value"]) != str(new_settings[idx]["value"]) ) or ( is_collection and list(map(dict, setting["value"])) != list(map(dict, new_settings[idx]["value"])) ): failed_settings.append(setting) if failed_settings: log.error("Failed to change settings: %s", failed_settings) return False log.debug("Settings configured successfully: %s", settings) return True