Audit Windows Network Settings with Powershell

We have been consolidating IT groups at the university for several years now. During this time we have to convert both clients and servers to use our central division Active Directory and other centralized services. However gathering all of the networking information can be quite the task and prone to error. One of the easiest ways I have found to gather all of this information is by running a script to generate CSV file of these settings.

I used this existing script I found over on techibee.com and took it a few steps further.

I added that ability to query Active Directory and find all the computers within an OU and the ability to adjust the filter. This can be handy if you want to find just windows servers or windows clients or just plain windows. I also fixed the output for multiple DNS servers or gateways to a CSV file as well as added some standard header and footers to make the screen output a bit cleaner. This script does require you to have the Active Directory Powershell Module Installed. It will save the CSV to the local directory from which the script is executed and report the path at the end of the screen output. This script should be run with a highly privileged user as it will need to query multiple remote computer using WMI and access Active Directory.

Script

Import-Module ActiveDirectory

$localpath = Get-Location;
$CSVFileName = $localpath.Path + "\Department-Network-Information.csv";

$ComputerName = Get-ADComputer -SearchBase "OU=Department,OU=Division,DC=domain,DC=local" -Filter {OperatingSystem -Like "Windows*"} -Property "Name";

$Results = @()

foreach ($Computer in $ComputerName)
{
    if(Test-Connection -ComputerName $Computer.Name -Count 1 -ea 0) 
    {
        $Networks = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $Computer.Name | ? {$_.IPEnabled};
        foreach ($Network in $Networks) 
        {
            $IPAddress  = $Network.IpAddress[0];
            $SubnetMask  = $Network.IPSubnet[0];
            $DefaultGateway = $Network.DefaultIPGateway;
            $DNSServers  = $Network.DNSServerSearchOrder;
            $IsDHCPEnabled = $false;
            If($network.DHCPEnabled) 
            {
                $IsDHCPEnabled = $true;
            }
            $MACAddress  = $Network.MACAddress;

            if ($DNSServers) 
            {
                $StringDNSServers = [string]::join("; ",$DNSServers);
            }
            else
            {
                $StringDNSServers = " ";
            }

            if($DefaultGateway)
            {
                $StringDefaultGateway = [string]::join("; ",$DefaultGateway);
            }
            else
            {
                $StringDefaultGateway = " ";
            }

            $ReturnedObj = New-Object -Type PSObject;
            $ReturnedObj | Add-Member -MemberType NoteProperty -Name ComputerName -Value $Computer.Name.ToUpper();
            $ReturnedObj | Add-Member -MemberType NoteProperty -Name IPAddress -Value $IPAddress;
            $ReturnedObj | Add-Member -MemberType NoteProperty -Name SubnetMask -Value $SubnetMask;
            $ReturnedObj | Add-Member -MemberType NoteProperty -Name Gateway -Value $StringDefaultGateway;
            $ReturnedObj | Add-Member -MemberType NoteProperty -Name IsDHCPEnabled -Value $IsDHCPEnabled;
            $ReturnedObj | Add-Member -MemberType NoteProperty -Name DNSServers -Value $StringDNSServers;
            $ReturnedObj | Add-Member -MemberType NoteProperty -Name MACAddress -Value $MACAddress;
            $ReturnedObj;
            $Results += $ReturnedObj;
        }
    }  
}

$Results | export-csv $CSVFileName -notype;

Write-Host
Write-Host "File Saved to: $CSVFileName";
Write-Host
Write-Host "Press any key to close ..."
$host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

Screen Output Example

ComputerName  : Computer1
IPAddress     : 194.90.128.89
SubnetMask    : 255.255.255.0
Gateway       : 194.90.128.254
IsDHCPEnabled : True
DNSServers    : 8.8.8.8; 8.8.4.4
MACAddress    : 18:13:73:2A:98:FA

ComputerName  : Computer2
IPAddress     : 194.90.128.92
SubnetMask    : 255.255.255.0
Gateway       : 194.90.128.254
IsDHCPEnabled : True
DNSServers    : 8.8.8.8; 8.8.4.4
MACAddress    : F8:B1:56:AC:FB:2E


File Saved to: D:\Powershell-Scripts\Department-Network-Information.csv

Press any key to close ...

CSV Output

"Computer1","194.90.128.89","255.255.255.0","194.90.128.254","True","8.8.8.8; 8.8.4.4","18:13:73:2A:98:FA"
"Computer2","194.90.128.92","255.255.255.0","194.90.128.254","True","8.8.8.8; 8.8.4.4","F8:B1:56:AC:FB:2E"

Read More

Powershell File Sharing Permissions Report

Often I am asked to verify folder permissions for a user in a specific place out on one of our servers. Typically this requires browsing out the folder and putting eyes on the permissions dialog box looking for a group on which the user is a member and then documenting it in the ticket. A very painful long boring process. This is where Powershell comes and saves the day. I wrote a very simple script to bring that information to me. It also gives nice output that I can directly copy into tickets to answer what groups has rights to what shares.

This prompts the user to “Enter a UNC Path” once entered goes and grabs the NTFS permissions as well as the SMB Share permissions

Powershell Code

Write-Host

$path = Read-host “Enter a UNC Path: ”
$pathparts = $path.split("\")
$ComputerName = $pathparts[2]
$ShareName = $pathparts[3]

Write-Host "File Sharing Permissions Report - $path"
Write-Host 

$acl = Get-Acl $path

Write-Host "File/NTFS Permissions"
Write-Host 

foreach($accessRule in $acl.Access)
{
    Write-Host "   " $accessRule.IdentityReference $accessRule.FileSystemRights
}
Write-Host 
Write-Host "Share/SMB Permissions"
Write-Host

    $Share = Get-WmiObject win32_LogicalShareSecuritySetting -Filter "name='$ShareName'" -ComputerName $ComputerName
    if($Share){
        $obj = @()
        $ACLS = $Share.GetSecurityDescriptor().Descriptor.DACL
        foreach($ACL in $ACLS){
            $User = $ACL.Trustee.Name
            if(!($user)){$user = $ACL.Trustee.SID}
            $Domain = $ACL.Trustee.Domain
            switch($ACL.AccessMask)
            {
                2032127 {$Perm = "Full Control"}
                1245631 {$Perm = "Change"}
                1179817 {$Perm = "Read"}
            }
            Write-Host "   $Domain\$user  $Perm"
        }
    }
Write-Host

Example Output

.\Get-Permissions-NTFS-SMB.ps1

Enter a UNC Path: : \\filesrv\Working Groups
File Sharing Permissions Report - \\filesrv\Working Groups

File/NTFS Permissions

    BUILTIN\Administrators FullControl
    DOMAIN\Domain Admins FullControl
    DOMAIN\Domain Users ReadAndExecute, Synchronize
    DOMAIN\Folder - File Server Admins FullControl

Share/SMB Permissions

   DOMAIN\Domain Admins  Full Control
   DOMAIN\Domain Users  Full Control

Read More

How to Use WMI Filtering to Improve Group Policy Administration

Group policy is one of the most versatile and powerful ways to manage your workstations in your domain. However, using just basic Group Policy to object relationship links you can limit the customization that is possible with group policy. Today I will show you how to add WMI (Windows Management Interface) Filtering to your group policy. This will allow you to build a kind of rule, and allow you to pick and choose which workstations get the policy and which don’t. My goal today is to apply my group policy to only workstations that start with the name of shs-exam. This is basically all the workstations that reside in our exam rooms and I would like them to have a special set of settings, however I want them to co-exist in my Active Directory structure in the proper ‘departmental’ organizational units that I already have.
Requirementswmi-query

Configuration

  1. Open your Group Policy Management Console and browse to WMI Filters in your Domain.
  2. Go ahead and Right Click on WMI Filters and select New
  3. Give the WMI Filter a nice descriptive name and give more detailed text in the Description if needed.
  4. To build your actual query for WMI you need to think of this as a question to ask the PC and if it returns any result then the Group Policy will be applied to it. The query I have built asks it to return name for the computer and if the name contains “SHS-EXAM” then it will return the name and get the group policy applied, if not then nothing happens and the group policy is skipped.
  5. group-policy-scope-wmi-filtering

  6. Add your WMI Query, mine is Select name from Win32_ComputerSystem WHERE NOT name LIKE “%SHS-EXAM%” This will basically select all computers that are not named “SHS-EXAM”
  7. Now press Save
  8. Now that we have successfully made the WMI Filter we need to apply it to the proper group policy, so go to your Group Policy Objects under your domain and select the one you wish to add the filter to.
  9. The last section on the screen should be WMI Filtering, just drop down the list and select the WMI Filter you just made

Reference Material

  • WQL (SQL for WMI) (Windows) – This is a great list of advanced operators and examples to get you close the the proper syntax
  • HOWTO: Leverage Group Policies with WMI Filters – This article explains in detail how to create a WMI filter to determine the scope of a Group Policy based on computer attributes.
  • Paessler WMI Tester – This tool can help you test your WMI queries before deploying them in Group Policy use. I use this tool all the time to help find information about a workstation.
  • Microsoft Win32 Classes Reference – This is a Microsoft’s reference for all of the objects and events for WMI. You can use this to find that specific settings you need to filter on.

Read More

Remote Shutdown / Logoff Script using WMI

Have you ever been sitting at your desk working very hard trying to getting some business analytics report finished for your administrative team, only to be interrupted by the everyday user unable to log on the machine because someone else locked it. Then you have to get up and walk down there and manually login and unlock the workstation. Well this is now a thing of the past for you if you have enabled WMI and have a domain or common credentials on your network. This script will simply allow you to unlock a workstation with out getting up from your desk. Unfortunately, I didn’t write this script but I use it about every other day to unlock a workstation. It has a few good options to allow you to either Logoff / Reboot / Shutdown the workstation. This can also be helpful when the user has locked up the PC and can’t get it to restart, you can send a command from the workstation you are at for that one to restart. In way you end up using this script it will only save you time, I found it to be very reliable and super fast for resolving the locked computer situation. Also, please browse though the code as it is well commented and you can get a greater understanding of how it exactly works.

'|| Remote Shutdown.vbs
'||
'|| Created by Harvey Hendricks, MCSE, A+,
'|| March 2001
'||
'|| email: hhendrks@aramco.com
'|| hhend@swbell.net
'||
'||
'|| Based on techniques and ideas from:
'|| SMS admin, SMS Installer, & WMI forums -> http://www.myITforum.com/forums
'|| Win32 Scripting -> http://cwashington.netreach.net/
'|| Microsoft Windows Script Technologies -> http://msdn.microsoft.com/scripting
'|| Microsoft Online Library -> http://msdn.microsoft.com/library/default.asp
'|| Microsoft VBScript 5.5 documentation
'|| and Microsoft WMI SDK
'||
'||~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'|| SCRIPT LOGIC FLOW:
'|| Collects computername from user, calls function to ping the computername
'|| to determine if it is accessible, if not then display message and exit
'|| otherwise continue.
'|| Collects desired action to perform from the user, does error checking on
'|| the input to determine if it is acceptable, if not then display message
'|| and exit otherwise continue.
'|| Set variables and output messages based on the action chosen. Calls
'|| Win32Shutdown with the appropriate variable. Displays success message
'|| and exits
'||
'|| Uses WMI Win32Shutdown method from the Win32_OperatingSystem class
'|| to perform different logoff / powerdown / reboot functions
'||
'|| Testing found the following values to be effective on Win32Shutdown:
'|| Action decimal binary
'|| Logoff 0 0000
'|| Force Logoff 4 0100
'|| Reboot 2 0010
'|| Force Reboot 6 0110
'|| Powerdown 8 1000
'|| Force Powerdown 12 1100
'||
'|| Notice that the third bit from the right appears to be the "FORCE" bit.
'||
'|| A value of 1 will do a shutdown, ending at the "It is safe to turn
'|| off your computer" screen. I have no use for this and did not test it.
'||
'||
'||NOTES: - tested under Windows 2000 Pro. with ACPI compliant systems -
'|| SHOULD work under Windows NT4 without modification IF the
'|| system has compatible versions of WSH / WMI / VBscripting
'||
'||Logoff / Powerdown / Reboot:
'|| Does not work if a password protected screen saver is active or
'|| there is data to save. Either way the system waits for user input.
'||
'||Force Logoff / Force Powerdown / Force Reboot:
'|| Does not work if a password protected screen saver is active, will wait
'|| for user input. Otherwise will close open applications without saving data.
'||
'\/~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


'/\/\/\/\/\/\/\/\/\/\/\/\/\/\ start function /\/\/\/\/\/\/\/\/\/\/\/\/\/'\/\/\/\/\/\/\/\/\/\/\/\/\/\/\______________/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
function Ping(byval strName)
dim objFSO, objShell, objTempFile, objTS
dim sCommand, sReadLine
dim bReturn

set objShell = WScript.CreateObject("Wscript.Shell")
set objFSO = CreateObject("Scripting.FileSystemObject")

'Set default return value
bReturn = false

'Create command line to ping and save results to a temp file
sCommand = "cmd /c ping.exe -n 3 -w 1000 " & strName & " > temp.txt"

'Execute the command
objShell.run sCommand, 0, true

'Get the temp file
set objTempFile = objFSO.GetFile("temp.txt")
set objTS = objTempFile.OpenAsTextStream(1)

'Loop through the temp file to see if "reply from" is found,
'if it is then the ping was successful
do while objTs.AtEndOfStream <> true
sReadLine = objTs.ReadLine
if instr(lcase(sReadLine), "reply from") > 0 then
bReturn = true
exit do
end if
loop

'Close temp file and release objects
objTS.close
objTempFile.delete
set objTS = nothing
set objTempFile = nothing
set objShell = nothing
set objFSO = nothing

'Return value
Ping = bReturn
end function
'/\/\/\/\/\/\/\/\/\/\/\/\/\/\ end function /\/\/\/\/\/\/\/\/\/\/\/\/\/'\/\/\/\/\/\/\/\/\/\/\/\/\/\/\______________/\/\/\/\/\/\/\/\/\/\/\/\/\/\/



'/\/\/\/\/\/\/\/\/\/\/\ Start Main body of script /\/\/\/\/\/\/\/\/\/\/\/'\/\/\/\/\/\/\/\/\/\/\/\_________________________/\/\/\/\/\/\/\/\/\/\/\/\/
'Get computer name to operate on
ComputerName=InputBox("Enter the Machine name of the computer" & vbCRLF _
& "you wish to Shutdown / Reboot / Logoff", _
"Remote Shutdown / Reboot / Logoff", _
"ComputerName")

'if Cancel selected - exit
If (ComputerName = "") Then Wscript.Quit

'change the name to uppercase
ComputerName=UCase(ComputerName)

'ping the computername to see if it is accessible
bPingtest = ping(Computername)

If bPingtest = FALSE Then
y = msgbox ("'" & ComputerName & "' is not accessible!" & vbCRLF _
& "It may be offline or turned off." & vbCRLF _
& "Check the name for a typo." & vbCRLF, _
vbCritical, ComputerName & " NOT RESPONDING")
Wscript.Quit
end IF

'Get the action desired
Action=InputBox( _
"Select Action to perform on " & ComputerName & vbCRLF & vbCRLF _
& " 1 - Logoff" & vbCRLF _
& " 2 - Force Logoff ( NO SAVE )" & vbCRLF _
& " 3 - Powerdown" & vbCRLF _
& " 4 - Force Powerdown ( NO SAVE )" & vbCRLF _
& " 5 - Reboot" & vbCRLF _
& " 6 - Force Reboot ( NO SAVE )" & vbCRLF & vbCRLF _
& "NOTE:" & vbCRLF _
& " Using Force will close windows" & vbCRLF _
& " without saving changes!", _
"Select action to perform on " & ComputerName, "")

'if Cancel selected - exit
If (Action = "") Then Wscript.Quit

'error check input
If (INSTR("1234567",Action)=0) OR (Len(Action)>1) then
y = msgbox("Unacceptable input passed -- '" & Action & "'", _
vbOKOnly + vbCritical, "That was SOME bad input!")
Wscript.Quit
end if

' set flag to disallow action unless proper input is achieved, 1 => go 0 => nogo
flag = 0

'set variables according to computername and action
Select Case Action
Case 1 'Logoff
x = 0
strAction = "Logoff sent to " & ComputerName
flag = 1
Case 2 'Force Logoff
x = 4
strAction = "Force Logoff sent to " & ComputerName
flag = 1
Case 3 'Powerdown
x = 8
strAction = "Powerdown sent to " & ComputerName
flag = 1
Case 4 'Force Powerdown
x = 12
strAction = "Force Powerdown sent to " & ComputerName
flag = 1
Case 5 'Reboot
x = 2
strAction = "Reboot sent to " & ComputerName
flag = 1
Case 6 'Force Reboot
x = 6
strAction = "Force Reboot sent to " & ComputerName
flag = 1
Case 7 'Test dialog boxes
y = msgbox("Test complete", vbOKOnly + vbInformation, "Dialog Box Test Complete")
flag = 0
Case Else 'Default -- should never happen
y = msgbox("Error occurred in passing parameters." _
& vbCRLF & " Passed '" & Action & "'", _
vbOKOnly + vbCritical, "PARAMETER ERROR")
flag = 0
End Select

'check flag
' if equal 1 (TRUE) then perform Win32Shutdown action on remote PC
' and display a confirmation message
' if not equal 1 (FALSE) then skip the action and script ends
if flag then
Set OpSysSet=GetObject("winmgmts:{(Debug,RemoteShutdown)}//" _
& ComputerName & "/root/cimv2").ExecQuery( _
"Select * from Win32_OperatingSystem where Primary=true")
for each OpSys in OpSysSet
OpSys.Win32Shutdown(x)
y = msgbox(strAction,vbOKOnly + vbInformation,"Mission Accomplished")
next
end If

'Release objects
set OpSys = nothing
set OpSysSet = nothing

Read More