I’ve recently been looking at extending the standard set of auditing (from the previous scripts mentioned in
Part 1
,
Part 2
, and
Part 3
) to include DHCP scope information, and IIS-based website information.
Before getting into DHCP and IIS, I run an audit of all services, like this:
# Get WMI data
$getservices = gwmi win32_service -ea 0 | select name, caption, startname, startmode;
$servicescount = ($getservices | measure-object).count;
# Convert service info into an array if only 1 service is found
if ($servicescount -eq 1) {
$temparray = @();
$temparray += $getservices;
$getservices = $temparray;
# Get WMI data
$getservices
=
gwmi
win32_service
-ea
0
|
select
name
,
caption
,
startname
,
startmode
;
$servicescount
=
(
$getservices
|
measure-object
)
.
count
;
# Convert service info into an array if only 1 service is found
if
(
$servicescount
-eq
1
)
{
$temparray
=
@
(
)
;
$temparray
+=
$getservices
;
$getservices
=
$temparray
;
}
$getservices
now contains all of your service information.
The next section gathers DHCP data, but checks the above variable,
$getservices
, for the DHCP Server service first.
I’ve used an “old-school” method to get the DHCP data, so that the script will work on all versions of PowerShell and Windows operating systems. There are some very good DHCP cmdlets in the later versions of PowerShell, but I can’t rely on all servers having the newest/compatible version.
# If the DHCP Server service is installed
if ($getservices | where {$_.name -eq "dhcpserver"}) {
# Retrieve DHCP dump of information, looking for the "add scope" line
$alldhcp = netsh dhcp server dump | select-string -pattern "dhcp server" | select-string -pattern "add scope"
# If DHCP scope data is found
if ($alldhcp) {
$getscopes = @();
foreach ($line in $alldhcp) {
# Split line to remove junk and create individual data fields in array
$scopetext = ($alldhcp -split "add scope")[1]
$scopearray = $line -split ' +(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)'
$templine = "" | select iprange, subnetmask, scopename, scopedescription;
$templine.iprange = ($scopearray[5]).trim()
$templine.subnetmask = ($scopearray[6]).trim()
$templine.scopename = ($scopearray[7]).trim('"')
$templine.scopedescription = ($scopearray[8]).trim('"')
$getscopes = $getscopes + $templine
$scopecount = ($getscopes | measure-object).count;
# Convert DHCP scope info into an array if only 1 scope is found
if ($scopecount -eq 1) {
$temparray = @();
$temparray += $getscopes;
$getscopes = $temparray;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# If the DHCP Server service is installed
if
(
$getservices
|
where
{
$_
.
name
-eq
"dhcpserver"
}
)
{
# Retrieve DHCP dump of information, looking for the "add scope" line
$alldhcp
=
netsh
dhcp
server
dump
|
select-string
-pattern
"dhcp server"
|
select-string
-pattern
"add scope"
# If DHCP scope data is found
if
(
$alldhcp
)
{
$getscopes
=
@
(
)
;
foreach
(
$line
in
$alldhcp
)
{
# Split line to remove junk and create individual data fields in array
$scopetext
=
(
$alldhcp
-split
"add scope"
)
[
1
]
$scopearray
=
$line
-split
' +(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)'
$templine
=
""
|
select
iprange
,
subnetmask
,
scopename
,
scopedescription
;
$templine
.
iprange
=
(
$scopearray
[
5
]
)
.
trim
(
)
$templine
.
subnetmask
=
(
$scopearray
[
6
]
)
.
trim
(
)
$templine
.
scopename
=
(
$scopearray
[
7
]
)
.
trim
(
'"'
)
$templine
.
scopedescription
=
(
$scopearray
[
8
]
)
.
trim
(
'"'
)
$getscopes
=
$getscopes
+
$templine
}
$scopecount
=
(
$getscopes
|
measure-object
)
.
count
;
# Convert DHCP scope info into an array if only 1 scope is found
if
(
$scopecount
-eq
1
)
{
$temparray
=
@
(
)
;
$temparray
+=
$getscopes
;
$getscopes
=
$temparray
;
}
}
}
# Check is IIS feature is installed
if (($features | where {$_.name -eq "IIS-WebServer"}) -ne $null) {
# Check for IIS7+ based websites
try {
$sites = get-childItem -path IIS:\Sites;
# If websites are found
if ($sites) {
# Loop thorugh each website found
foreach ($site in $sites) {
# Loop through and gather binding information
foreach ($binding in ($site.bindings.collection | where {$_.protocol -like "http*"})) {
$tempiis = "" | select websitename, apppool, enabledprotocols, bindinghostname, bindingport, bindingipaddress;
$tempiis.websitename = $site.name
$tempiis.apppool = $site.applicationpool
$tempiis.enabledprotocols = $site.enabledprotocols
$bindinginformation = $binding.bindinginformation.split(":");
$tempiis.bindinghostname = $bindinginformation[2]
$tempiis.bindingport = $bindinginformation[1]
$tempiis.bindingipaddress = $bindinginformation[0]
$getiis = $getiis + $tempiis;
} catch {}
# Check for IIS6 based websites
try {
$sites = gwmi -namespace "root/MicrosoftIISv2" -class 'IIsWebServerSetting';
# If websites are found
if ($sites) {
# Loop through each website found
foreach ($site in $sites) {
# Loop through and gather binding information
foreach ($binding in $site.serverbindings) {
$tempiis = "" | select websitename, apppool, enabledprotocols, bindinghostname, bindingport, bindingipaddress;
$tempiis.websitename = $site.servercomment;
$tempiis.apppool = $site.apppoolid;
$tempiis.enabledprotocols = $site.enabledprotocols;
$tempiis.bindinghostname = $binding.hostname
$tempiis.bindingport = $binding.port
$tempiis.bindingipaddress = $binding.ip
$getiis = $getiis + $tempiis;
} catch {}
# Convert IIS into an array if only 1 scope is found
$iiscount = ($getiis | measure-object).count;
if ($iiscount -eq 1) {
$temparray = @();
$temparray += $getiis;
$getiis = $temparray;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
$getiis
=
@
(
)
# Check is IIS feature is installed
if
(
(
$features
|
where
{
$_
.
name
-eq
"IIS-WebServer"
}
)
-ne
$null
)
{
# Check for IIS7+ based websites
try
{
$sites
=
get-childItem
-path
IIS
:
\
Sites
;
# If websites are found
if
(
$sites
)
{
# Loop thorugh each website found
foreach
(
$site
in
$sites
)
{
# Loop through and gather binding information
foreach
(
$binding
in
(
$site
.
bindings
.
collection
|
where
{
$_
.
protocol
-like
"http*"
}
)
)
{
$tempiis
=
""
|
select
websitename
,
apppool
,
enabledprotocols
,
bindinghostname
,
bindingport
,
bindingipaddress
;
$tempiis
.
websitename
=
$site
.
name
$tempiis
.
apppool
=
$site
.
applicationpool
$tempiis
.
enabledprotocols
=
$site
.
enabledprotocols
$bindinginformation
=
$binding
.
bindinginformation
.
split
(
":"
)
;
$tempiis
.
bindinghostname
=
$bindinginformation
[
2
]
$tempiis
.
bindingport
=
$bindinginformation
[
1
]
$tempiis
.
bindingipaddress
=
$bindinginformation
[
0
]
$getiis
=
$getiis
+
$tempiis
;
}
}
}
}
catch
{
}
# Check for IIS6 based websites
try
{
$sites
=
gwmi
-namespace
"root/MicrosoftIISv2"
-class
'IIsWebServerSetting'
;
# If websites are found
if
(
$sites
)
{
# Loop through each website found
foreach
(
$site
in
$sites
)
{
# Loop through and gather binding information
foreach
(
$binding
in
$site
.
serverbindings
)
{
$tempiis
=
""
|
select
websitename
,
apppool
,
enabledprotocols
,
bindinghostname
,
bindingport
,
bindingipaddress
;
$tempiis
.
websitename
=
$site
.
servercomment
;
$tempiis
.
apppool
=
$site
.
apppoolid
;
$tempiis
.
enabledprotocols
=
$site
.
enabledprotocols
;
$tempiis
.
bindinghostname
=
$binding
.
hostname
$tempiis
.
bindingport
=
$binding
.
port
$tempiis
.
bindingipaddress
=
$binding
.
ip
$getiis
=
$getiis
+
$tempiis
;
}
}
}
}
catch
{
}
}
# Convert IIS into an array if only 1 scope is found
$iiscount
=
(
$getiis
|
measure-object
)
.
count
;
if
(
$iiscount
-eq
1
)
{
$temparray
=
@
(
)
;
$temparray
+=
$getiis
;
$getiis
=
$temparray
;
}
Hi Kamal,
I follow regulary your post. Very interresting. But for this one, just a question : Why use netsh to query info about DCHP ? I know that Netsh is a swiss knife DOS cmd. but in 2020, using the cmdlets of DHCPServer PS module seems to be more appropriate.
regards
Olivier
Hi Olivier,
I tried to articulate it in the post, but maybe I was being too subtle?
In my experience (working across
a lot
of different companies) is that very few of them run the latest version of anything. Latest version (or even n-1 version) of Windows Server? Rare. Similarly, the PowerShell versions usually never get upgraded. Your experience might be different – but having the latest PS modules in place is an extremely rare sight for me, and upgrading PowerShell across hundreds or thousands of servers is also next to impossible to get any traction on.
As an example, one of my recent assignments had me reviewing 160+ DHCP servers in a single domain (most running Server 2008 R2, and PowerShell v3 – but also some Windows Server 2003 in the mix). Not a small number of PS upgrades required.
So, with that in mind, I (usually) am forced to write more “universal” and backwards-compatible PowerShell scripts that will work on any version of PowerShell and any version of Windows Server; in that way, I know they will always work and give me the results I need.
It’s pretty frustrating not having the latest and greatest, but sometimes you just need to work within the boundaries of what’s in front of you.