STOP THAT Print Spooler!

Scenario: With some of the latest exploits, stop that print spooler on your servers if its unneeded

Solution: PowerShell Scriptlets

If you are on the server, run the following:

Set-service Spooler -startuptype disabled
stop-service Spooler
get-service spooler


If you want to remotely run the commands, like the big bad admin that you are, run the following:

$s = "ExServer1","ExServer2"
$s | %{
    $n = $_
    "Disabling Spooler on $_"

    Invoke-Command -ComputerName $n -ScriptBlock { Set-service Spooler -startuptype disabled }
    Invoke-Command -ComputerName $n -ScriptBlock { stop-service Spooler}


PowerShell Scriptlets to check if NLA is enabled for Remote Desktop

Scenario: You want to see if  NLA (Network Level Authentication) is enabled on all of your servers for Remote Desktop.

The PowerShell code below is not a .ps1, although you can make a .ps1 out of it if you would like.  I like to teach working  “within” PowerShell, not just being a script monkey.

In order to run the code, you will need to open Powershell OR Powershell ISE with an account with elevated permissions to access your servers (Run-AS).  The purpose of working within PowerShell is so that you can  reuse/recycle the code below to do other things too.
Once PowerShell is opened, follow the steps:
  1. Build your $Servers Variable — Select a method to populate $Servers
  2. Run the Query to build the $Results table
  3. Display the $Results — Select a method



#1. Build your $Servers Variable — Select one of the methods below to populate $Servers

  $Servers = “ExSrv1″,”ExSrv2”   #Feel free to list the servers by name

        $Servers = Import-csv C:tempservers.csv | Select -expandproperty Name   #Create a CSV with a NAME column header

        $Servers =  get-adcomputer -searchbase “OU=Servers,DC=steve,DC=com” -properties Name -Filter *|  Select -ExpandProperty Name  #Pull a list of AD Computers via AD PowerShell

#2. Run the query to build the $Results variable 

$Results = @()
$Servers | %{
    #Collect NLA Data
    $name = $_
    $NLA = Get-WmiObject -class “Win32_TSGeneralSetting” -Namespace rootcimv2terminalservices -ComputerName $name -Filter “TerminalName=’RDP-tcp'” | Select -ExpandProperty UserAuthenticationRequired
    #Display in PowerShell Screen
    “$name : NLA_Enabled:$(If($NLA -eq 1){“Yes”}else{“No”})”

    #Add the data to the $results variable
    $ServerObj = New-Object PSObject
    $ServerObj | Add-Member NoteProperty -Name “Server” -value $name
    $ServerObj | Add-Member NoteProperty -Name “NLA_Enabled” -value $(If($NLA -eq 1){“Yes”}else{“No”})
    $Results += $ServerObj
    #Reset Variable
    $Name = $null
    $NLA = 0

#3. Display the $Results –  Select a method


    #-or Export the Results –
        $Results | Export-CSV C:tempresults.csv

    #-or Email the Results –
        $Header = @”
        TABLE {border-width: 1px; border-style: solid; border-color: black; border-collapse: collapse;}
        TH {border-width: 1px; padding: 3px; border-style: solid; border-color: black; background-color: #6495ED;}
        TD {border-width: 1px; padding: 3px; border-style: solid; border-color: black; text-align: center;}
        tr:nth-child(odd) { background-color:#F2F2F2;}
        tr:nth-child(even) { background-color:white;}
        $body =”$($results | ConvertTo-Html -Head $header)”
        $smtp = “”
        $to = “”
        $from = “”
        $subject = “Results of NLA”
        send-MailMessage -SmtpServer $smtp -To $to -From $from -Subject $subject -Body $body -BodyAsHtml -Priority high

PowerShell: Find and copy text from multiple files

Scenario: You have to find a specific string of text in multiple files.  We are going to search for the term “steve” against all RPC Client Access logs for today.



$files = get-childitem -path “\ExSrv1c$Program FilesMicrosoftExchange ServerV15LoggingRPC Client Access”
$result = @()
$term = “steve”

#Perform the Search

$files | Where CreationTime -gt 9/6/2018| Sort CreationTime -Descending | %{
       $F = $_.fullname
       $result += select-string $f -pattern $term | %{$_.Line}

#Export Results

$result | out-file C:tempresults.txt

Disconnect Terminal Sessions via PowerShell on Remote ServersComputers

Scenario:  You want to disconnect all remote sessions on ServerComputers via PowerShell remotely.


#Disconnect Terminal Sessions via PowerShell################

#Gather the Servers in the $Servers Variable

$Servers = get-exchangeserver Exch* | Select -expandproperty Name

#Gather the Sessions
$TS = $Servers | %{
$computer = $_
quser /server:$computer 2>&1 | Select-Object -Skip 1 | ForEach-Object {
                $CurrentLine = $_.Trim() -Replace ‘s+’,’ ‘ -Split ‘s’
                $HashProps = @{
                    UserName = $CurrentLine[0]
                    ComputerName = $Computer

                # If session is disconnected different fields will be selected
                if ($CurrentLine[2] -eq ‘Disc’) {
                        $HashProps.SessionName = $null
                        $HashProps.Id = $CurrentLine[1]
                        $HashProps.State = $CurrentLine[2]
                        $HashProps.IdleTime = $CurrentLine[3]
                        $HashProps.LogonTime = $CurrentLine[4..6] -join ‘ ‘
                        $HashProps.LogonTime = $CurrentLine[4..($CurrentLine.GetUpperBound(0))] -join ‘ ‘
                } else {
                        $HashProps.SessionName = $CurrentLine[1]
                        $HashProps.Id = $CurrentLine[2]
                        $HashProps.State = $CurrentLine[3]
                        $HashProps.IdleTime = $CurrentLine[4]
                        $HashProps.LogonTime = $CurrentLine[5..($CurrentLine.GetUpperBound(0))] -join ‘ ‘

                New-Object -TypeName PSCustomObject -Property $HashProps | Select-Object -Property UserName,ComputerName,SessionName,Id,State,IdleTime,LogonTime,Error


#Disconnect the Sessions
$TS | %{
    $id = $
    $Name = $_.computerName
    $User = $_.Username
    rwinsta $ID /server:$name
    Write-Host “Session $Id for $User on $Name successfully disconnected”


Scheduled Task doesn’t allow powershell script to convert/save XLSX file to a CSV file

Scenario:  You have a PowerShell script running that will convert an .XLSX document into a .CSV Document.  When you run it natively in PowerShell, the script works fine and the document converts.  When you attempt to run it in Task Scheduler, it doesn’t convert and  create the new document.

Solution:  Create a Desktop folder in the following two directories and run the scheduled task again.:

  1. C:WindowsSysWOW64configsystemprofile

Remove a user/group permission on an AD Object via PowerShell

Scenario: You want to remove a users permission to an AD Object via PowerShell. This is the equivalent of opening Active Directory Users and Computers, finding your AD object (user, computer, ect), and removing the users permission from the Security Tab.

Scriptlets:  We are going to remove the user   domainjdoe from the AD Computer  test_computer.


#Set these variables
$DistinguishedName = "CN=test_computer,OU=Test,OU=Domain,DC=com"
$user = "domainjdoe"

#Collect the current ACL
$Acl = Get-Acl $DistinguishedName 

#Loop each access permission in the ACL
foreach ($access in $acl.Access) {
        if ($access.IdentityReference.Value -eq $user) {

#Set the ACL Back to the AD Object
set-acl $DistinguishedName  -AclObject $acl


Lets say you wanted to do this for every ADObject in a specific OU, run the following

#Set these Variables
$strOU = "CN=test,DC=Domain,DC=Com"
$Obj = get-adobject -searchbase $strOU -properties DistinguishedName,DisplayName -Filter * | Select DisplayName,DistinguishedName
$Obj = $obj | Sort DisplayName
$user = "domainjdoe"
$counter = 0

#Set AD as the location to find the user objects.
Set-Location ad:

#Loop it
$Obj | Select -first 5 | %{
#Increase counter
#Display Output
$counter / $($obj.count): Removing $User from $_.DisplayName - $_.DistinguishedName
#Get the current ACL for the AD Object
$DN = $_.DistinguishedName
$Acl = Get-Acl $DN 

#Loop each Access Level in the ACL And Remove for the User
foreach ($access in $acl.Access) {
       if ($access.IdentityReference.Value -eq $user) {$acl.RemoveAccessRule($access)} }

#Setting the Modified ACL back to the AD Object
set-acl $DN  -AclObject $acl

#reset variables
$ACL = $Null
$DN = $null



Script: Set NTFS Permissions on a Folder via PowerShell

Scenario: You want to set NTFS permissions on a folder via Powershell. You want the permissions to inherit down to SubFolders and files as well.


$folder = "\FileSvr1filestest12345"
$user = "DomainJdoe"

# Get the ACL for an existing folder
$existingAcl = Get-Acl -Path $folder

# Set the permissions that you want to apply to the folder
$permissions = $user, 'Read,Modify', 'ContainerInherit,ObjectInherit', 'None', 'Allow'

# Create a new FileSystemAccessRule object
$rule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule -ArgumentList $permissions

# Modify the existing ACL to include the new rule

# Apply the modified access rule to the folder
$existingAcl | Set-Acl -Path $folder


PowerShell: Search Multiple servers to see if a specific program is installed

Scenario:  You want to quickly search multiple remote servers to see if a specific program is installed.

Script: The following script checks to see if Wireshark is installed on any of our Exchange servers.

#Declare Server Variable
$Ex2013 = Get-exchangeserver ex* | Select -expandproperty Name

#Perform the Query against each server
$Ex2013 | %{"Checking WireShark on $_";Invoke-Command -Computer $_ -ScriptBlock {

#Declare App
$appToMatch = '*Wireshark*'

#Determine Uninstall Directory
if ([IntPtr]::Size -eq 4) {
        $regpath = 'HKLM:SoftwareMicrosoftWindowsCurrentVersionUninstall*'
    } else {
        $regpath = @(

#Get all Programs Installed
$1 = Get-ItemProperty $regpath | .{process{if($_.DisplayName -and $_.UninstallString) { $_ } }} | Select DisplayName, Publisher, InstallDate, DisplayVersion, UninstallString |Sort DisplayName

#Filter based on program
$result = $1 | where {$_.DisplayName -like $appToMatch}

#Display the result if found
If($result -ne $null){
    Write-Host "
    The following matching $appToMatch are Installed on $($env:computername) " -ForegroundColor Yellow
    Write-Host "$($result.displayName)
    " -ForegroundColor Yellow

PowerShell Script-lets to install Prerequisites for Exchange 2016 Remotely

Scenario: You want a script to install the Prerequisites for Exchange 2016 on Windows Server 2016.  Here is a few of the PowerShell commands we ran remotely for each server.


Gather your Servers

#Collect Servers into a Variable
$strOU = "OU=Exchange2016,DC=XYZ,DC=COM"
$servers = get-adcomputer -searchbase $strOU -properties Name -Filter *|  where {$ -like "Ex16-*"} | Select -ExpandProperty Name

Turn off the Windows Firewall  (We kept our Firewall turned on with multiple rules, but incase you need to disable it this is how you do it)

#turn off Windows Firewall
$servers | %{"Turning Windows Firewall off on $_";Invoke-Command -Computer $_ -ScriptBlock {Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled False}}

Place all Installer Files (C:sharesoftware) into a folder and copy them to each server under C:Software.

$servers | %{MD \$_c$software}

#Copy Files to a Server -  Put all Setup files you wish to install in this directory and copy to the server.
$servers | %{"Copying files to $_";Copy-Item C:sharesoftware* \$_C$software}

Disable User Account Control

#Disable UserAccountControl on a Server
$servers | %{"Disable UserAccountControl on $_"; Invoke-Command -Computer $_ -ScriptBlock {New-ItemProperty -Path HKLM:SoftwareMicrosoftWindowsCurrentVersionpoliciessystem -Name EnableLUA -PropertyType DWord -Value 0 -Force}}

Install Windows Features

#Install Windows Features
$servers | Sort | %{"Installing Windows Features on $_"; Invoke-Command -Computer $_ -ScriptBlock {Install-WindowsFeature NET-Framework-45-Features, RPC-over-HTTP-proxy, RSAT-Clustering, RSAT-Clustering-CmdInterface, RSAT-Clustering-Mgmt, RSAT-Clustering-PowerShell, Web-Mgmt-Console, WAS-Process-Model, Web-Asp-Net45, Web-Basic-Auth, Web-Client-Auth, Web-Digest-Auth, Web-Dir-Browsing, Web-Dyn-Compression, Web-Http-Errors, Web-Http-Logging, Web-Http-Redirect, Web-Http-Tracing, Web-ISAPI-Ext, Web-ISAPI-Filter, Web-Lgcy-Mgmt-Console, Web-Metabase, Web-Mgmt-Console, Web-Mgmt-Service, Web-Net-Ext45, Web-Request-Monitor, Web-Server, Web-Stat-Compression, Web-Static-Content, Web-Windows-Auth, Web-WMI, Windows-Identity-Foundation,RSAT-ADDS}}

Set the Page File Size to 32GB

#Setting Page File Size on Servers
    $servers | %{"Setting Page File Size on $_"; Invoke-Command -Computer $_ -ScriptBlock {
    [int]$InitialSize = 32778
    [int]$MaximumSize = 32778
    $ComputerSystem = $null
    $CurrentPageFile = $null
    $modify = $false
    $ComputerSystem = Get-WmiObject -Class Win32_ComputerSystem -EnableAllPrivileges
    if ($ComputerSystem.AutomaticManagedPagefile) {$ComputerSystem.AutomaticManagedPagefile = $false; $ComputerSystem.Put()}
    $CurrentPageFile = Get-WmiObject -Class Win32_PageFileSetting
    if ($CurrentPageFile.InitialSize -ne $InitialSize) {$CurrentPageFile.InitialSize = $InitialSize;$modify = $true}
    if ($CurrentPageFile.MaximumSize -ne $MaximumSize) {$CurrentPageFile.MaximumSize = $MaximumSize;$modify = $true}
    if ($modify) { $CurrentPageFile.Put()}

Install Unified Communications Managed API Runtime. The installer was renamed to UCMA.exe.

#Install Unified Communications Managed API Runtime silently
$servers | %{"Installing UCMA on $_"; Invoke-Command -Computer $_ -ScriptBlock {
    #Set Variables
    $file = "C:softwareUcma.exe" 
    #check to see if its installed
    if (Get-ItemProperty "HKLM:SoftwareMicrosoftWindowsCurrentVersionUninstallUCMA4" -ErrorAction SilentlyContinue) { 
        Write-host "Unified Communications Managed API 4.0 Runtime is already installed." -ForegroundColor Cyan 
        } else {
               If (Test-Path $file){ 
                    Write-host "The installer file exists:$file"  -ForegroundColor Green
                     Write-Host "Installing Microsoft UM API..." -ForegroundColor yellow 
                     $arg = "/quiet /norestart" 
                     $status = (Start-Process $file -ArgumentList $arg -Wait -PassThru).ExitCode 
                     if ($status -eq 0) { write-host "Successfully installed $file" -ForegroundColor Green } 
                     if ($status -ne 0) { write-host "Failed!" -ForegroundColor Red }                           
            } else {Write-host "$file does not exist" -ForegroundColor red}

Restart your Servers

#Restart Servers
$servers | %{"Restarting $_";Restart-computer $_ -force}