Tuesday, September 25, 2018

Automatically load RSAT as a different user

For a while now I've wanted to load the RSAT (Windows Remote Server Administration Tools) tool I use daily via a script at logon, but as my admin user account, not my normal logon.  There are numerous posts on the web about doing that but with the later versions of PowerShell most of those don't work.  Windows 10 doesn't help.

I'm sure there are better ways of doing this but after trying the suggestions I found on the web I hit on a combination that works.  The full script and all future updates are on my PowerShell Library site here: https://www.powershellgallery.com/profiles/Kcmjr

I call the script "RSAT-As-Admin.ps1".  It includes a list of RSAT tools that you must adjust to suit your needs.  The way it's written you can add additional executables easily if desired.

Here is the code from release v1.00.  Updates will be posted at the link,above.


Param(
    [Switch]$Console = $false           #--[ Set to true to enable local console result display. Defaults to false ]--
)
<#==============================================================================
         File Name : RSAT-As-Admin.ps1
   Original Author : Kenneth C. Mazie (kcmjr AT kcmjr.com)
                   :
       Description : Automatically loads specified Windows RSAT AD Admin tools using the user ID you specify.
                   :
             Notes : Normal operation is with no command line options. The list of RSAT tools below
                   : should be commented in/out as needed.  Tested on Windows 10 1803 only.
                   :
         Arguments : Command line options for testing:
                   : - "-console $true" will enable local console echo
                   :
          Warnings : None
                   :  
             Legal : Public Domain. Modify and redistribute freely. No rights reserved.
                   : SCRIPT PROVIDED "AS IS" WITHOUT WARRANTIES OR GUARANTEES OF
                   : ANY KIND. USE AT YOUR OWN RISK. NO TECHNICAL SUPPORT PROVIDED.
                   : That being said, please let me know if you find bugs or improve the script.
                   :
           Credits : Code snippets and/or ideas came from many sources including but
                   : not limited to the following:   n/a
                   :
    Last Update by : Kenneth C. Mazie    
   Version History : v1.0 - 09-24-18 - Original
    Change History : v1.1 - 00-00-00 -
                   :
==============================================================================#>
<#PSScriptInfo
.VERSION 1.00
.GUID 75f90821-5799-44ed-af38-bc4e05f9e385
.AUTHOR Kenneth C. Mazie (kcmjr AT kcmjr.com)
.DESCRIPTION
Automatically loads specified Windows RSAT AD Admin tools using the user ID you specify. 
#>
#Requires -Version 5.1

Clear-Host
$Script:Credential = ""
$ThisDomain = (Get-ADDomain).DNSroot
$Credential = Get-Credential #-Credential "domain\username"

#------------------------------------------------------------------------------------------------------
$ToolList = @()   #--[ Array of separate items to allow easy addition or removal. Comment out lines for tools you don't want loaded  ]--
#$ToolList += "dsac.exe"             #--[ Active Directory Administrative Center         ]--
$ToolList += "dsa.msc"              #--[ Active Directory Users and Computers           ]--
#$ToolList += "domain.msc"           #--[ Active Directory Domains and Trusts            ]--
#$ToolList += "dssite.msc"           #--[ Active Directory Sites and Services            ]--
$ToolList += "gpmc.msc"             #--[ Group Policy Management                        ]--
$ToolList += "dhcpmgmt.msc"         #--[ DHCP Manager                                   ]--
$ToolList += "dnsmgmt.msc"          #--[ DNS Manager                                    ]--
$ToolList += "dfsmgmt.msc"          #--[ DFS Manager                                    ]--
#$ToolList += "vmw.exe"              #--[ Volume Activation Tools                        ]--
#$ToolList += "printmanagement.msc"  #--[ Print Management                               ]--
#$ToolList += "nlbmgr.exe"           #--[ Network Load Balancing Manager                 ]--
#$ToolList += "secpol.msc /s"        #--[ Local Security Policy                          ]--
#$ToolList += "iscsicpl.exe"         #--[ iSCSI Initiator                                ]--
#$ToolList += "fsrm.msc"             #--[ File Server Resource Manager                   ]--
#$ToolList += "Cluadmin.msc"         #--[ Failover Cluster Manager                       ]--
#$ToolList += "ClusterUpdateUI.exe"  #--[ Cluster Aware Updating                         ]--
#$ToolList += "certsrv.msc"          #--[ Certification Authority                        ]--
#$ToolList += "adsiedit.msc"         #--[ ADSI Edit                                      ]--
#--------------------------------------------------------------------------------------------------------

$ToolPath = "c:\windows\system32\"
[Environment]::CurrentDirectory = (Get-Location -PSProvider FileSystem).ProviderPath

$Result = disable-UEV
#--[ Microsoft UE-V (User Experience Virtualization) is a tool that enables users to move from one Windows  ]--
#--[ device to another and maintain the same operating system (OS) and applications settings. (i.e roaming) ]--
If ($Result -Like "*successfully*"){
    If ($Console){Write-host $Result -Foregroundcolor Green}
}Else{
    If ($Console){Write-Host "There was an error disabling UE-V" -ForegroundColor Red}
}

ForEach ($Tool in $ToolList){
    write-host "`n-------------------------------------------------------------------`n"
    If ($Tool.Split(" ").count -gt 1){    #--[ There is a space in the tool command meaning some sort of argument ]--
        $Arg = $Tool.Split(" ")[1]
        $Tool = $Tool.Split(" ")[0]
           
        If ($Tool.Split('.')[1] -eq "exe"){
            $Command = 'Start-Process "'+($ToolPath+$Tool+" "+$Arg)+'" -verb runas'
        }Else{
            $Command = 'Start-Process mmc.exe -verb runas -argument "'+($ToolPath+$Tool+" "+$Arg)+'"'
        }   
    }Else{
        If ($Tool.Split('.')[1] -eq "exe"){
            $Command = 'Start-Process '+($ToolPath+$Tool)+' -verb runas'
        }Else{
            $Command = 'Start-Process mmc.exe -verb runas -argument '+($ToolPath+$Tool)
        }   
    }

    #$Command  #--[ Un-comment to display the resultant command line ]--

    If (Test-Path -Path ($ToolPath+$Tool)) {
        Start-Process powershell.exe -Credential $Credential -NoNewWindow -ArgumentList $Command
        If ($Console){write-host "Tool $Tool is starting..." -ForegroundColor Green}
    }Else{
        If ($Console){write-host "Tool $Tool was not found..." -ForegroundColor Red}
    } 
 
}


Monday, August 20, 2018

Domain Disk Check

As mentioned previously I am now publishing my scripts on the MS PowerShell Gallery site.   I'll put descriptions here for the benefit of anyone who finds them useful but the scripts are at the Gallery.

This script uses WMI to poll the current domain and extract disk statistics.

Output is gathered in HTML format and emailed to a list of recipients.  Output can be all systems (full) or only systems that are below preset threshold (brief).   Also you can select just servers, just PCs, or a third group which is currently coded for security surveillance servers.

An external XML configuration file is used to allow customization of the run time parameters. 

The output is color coded to allow for easy viewing.  Thresholds are adjustable via the XML file.

The script is called "DomainDiskReport.ps1" and is best found at the library main page at https://www.powershellgallery.com/profiles/Kcmjr/

Here is an example of the script email results using the "brief" option.  The "brief" option will only list systems that trigger the thresholds:


Wednesday, March 7, 2018

Scripts on the PowerShell Gallery

I have started posting my scripts on the PowerShell Gallery here: https://www.powershellgallery.com/profiles/Kcmjr/

I'll still try to post them here so I can ramble on about what they do but I'm using the Gallery as the primary location now.

Friday, December 1, 2017

Track time sync across all domain controllers

I hate always harping on Windows time but since it sucks I can't help myself.

I wrote this script to watch the time on all our domain controllers, compare it, and alert me if it's off.

Be aware that this version doesn't have a window of larger than 1 minute.  I plan to fix that later.

Same as always, create the xml config file in the same folder.  See the end of the script for parameters for the file.  Use at your own risk.  Feel free to do what you want with the script (It would be great if you leave my name associated with this and any other scripts I write, but thats up to you.)

NOTE: Please use this as reference ONLY for now.  Until I can add a trigger window all this will do is spam you all week!

Param(
      [bool]$Console = $false
      )
<#==============================================================================
          File Name : DCTimeTest.ps1
    Original Author : Kenneth C. Mazie
                    :
        Description : Identifies all domain controllers and polls them for current time, then compares.
                    :
              Notes : Normal operation is with no command line options. 
                    :
   Optional argument: -Console $true (displays runtime info on console)
                    :
           Warnings : None
                    :  
              Legal : Public Domain. Modify and redistribute freely. No rights reserved.
                    : SCRIPT PROVIDED "AS IS" WITHOUT WARRANTIES OR GUARANTEES OF
                    : ANY KIND. USE AT YOUR OWN RISK. NO TECHNICAL SUPPORT PROVIDED.
                    :
            Credits : Code snippets and/or ideas came from many sources including but
                    :   not limited to the following:
                    :
     Last Update by : Kenneth C. Mazie
    Version History : v1.0 - 11-30-17 - Original
     Change History : v1.1 - 00-00-00 - Coming soon. Expected to allow finer comparison of minute differences.
                    :
#===============================================================================#>
#requires -version 5.0

Clear-host
$ErrorActionPreference = "silentlycontinue"
$Computer = $Env:ComputerName
$ScriptName = ($MyInvocation.MyCommand.Name).split(".")[0]
$Script:ConfigFile = "$PSScriptRoot\$ScriptName.xml"

Import-Module ActiveDirectory
 
$Script:Message = @()
$Script:MError = 0
$Script:HError = 0
$Script:LoopCount = 1

#--[ Add header to email report ]--
$Script:ReportBody = @()
$Script:ReportBody += '
<style type="text/css">
      table.myTable { border:5px solid black;border-collapse:collapse; }
    table.myTable td { border:2px solid black;padding:5px}
      table.myTable th { border:2px solid black;padding:5px;background: #949494 }
      table.bottomBorder { border-collapse:collapse; }
      table.bottomBorder td, table.bottomBorder th { border-bottom:1px dotted black;padding:5px; }
      tr.noBorder td {border: 0; }
</style>'

$Script:ReportBody +=
'<table class="myTable">
<tr class="noBorder"><td colspan=2><center><h1>- Domain Controller Time Sync Error -</h1></td></tr>
<tr class="noBorder"><td colspan=2><center>A time synchronization error has been detected on a domain controller.</td></tr>
<tr><th>Domain Controller</th><th>Detected Time</th></tr>
'

#--[ Read and load configuration file ]-------------------------------------
If (!(Test-Path $Script:ConfigFile)){       #--[ Error out if configuration file doesn't exist ]--
    Write-Host "---------------------------------------------" -ForegroundColor Red
    Write-Host "--[ MISSING CONFIG FILE.  Script aborted. ]--" -ForegroundColor Red
    Write-Host "---------------------------------------------" -ForegroundColor Red
    break
}Else{
      [xml]$Script:Configuration = Get-Content "$PSScriptRoot\$ScriptName.xml"      #--[ Load configuration ]--
     
    $Script:DebugEmail = $Script:Configuration.Settings.Email.Debug
    $Script:EmailTo = $Script:Configuration.Settings.Email.To
    $Script:EmailFrom = $Script:Configuration.Settings.Email.From
    $Script:Subject = $Script:Configuration.Settings.Email.Subject
    $Script:EmailHTML = $Script:Configuration.Settings.Email.HTML
    $Script:UserName = $Script:Configuration.Settings.Credentials.Username
    $Script:EncryptedPW = $Script:Configuration.Settings.Credentials.Password
    $Script:Base64String = $Script:Configuration.Settings.Credentials.Key
    $Script:SmtpServer = $Script:Configuration.Settings.Email.SmtpServer
    $Script:UserName = $Script:Configuration.Settings.Credentials.Username
    $Script:EncryptedPW = $Script:Configuration.Settings.Credentials.Password
    $Script:Base64String = $Script:Configuration.Settings.Credentials.Key  
    $ByteArray = [System.Convert]::FromBase64String($Script:Base64String);
    $Script:Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $Script:UserName, ($Script:EncryptedPW | ConvertTo-SecureString -Key $ByteArray)
}    
#-------------------------------------------------------------------------------

Function eMail {
    If ($Console){Write-Host "-- Sending Email" -ForegroundColor Yellow}
    $SMTP = new-object System.Net.Mail.SmtpClient($Script:SmtpServer)
    $Email = New-Object System.Net.Mail.MailMessage
    $Email.Body = $Script:ReportBody
    $Email.IsBodyHtml = $Script:EmailHTML
    $Email.To.Add($Script:EmailTo)
    $Email.From = $Script:EmailFrom
    $Email.Subject = $Script:Subject
    $SMTP.Send($Email)
    $Email.Dispose()
    $SMTP.Dispose()     
}

Function GetTimes {
    If ($Console){Write-Host "`nGetting Data..." -ForegroundColor Yellow}
    $Script:HourResults = @()
    $Script:MinuteResults = @()
    $FGColor = "#000000"
    $BGColor = "#bbbbbb"
    $BGColorRed = "#bbbbbb"
    $BGColorOra = "#bbbbbb"
    $BGColorYel = "#bbbbbb"
    $Script:RunSummary = @()
   
    foreach($DC in $Script:DcList){
        if ($DC.Name -ne $Env:computername){
            try{
                If ($Console){Write-Host "-- Polling:"$DC.Name.PadRight(13," ") -ForegroundColor cyan -NoNewline }
                $Data = @(Get-WmiObject -Class win32_localtime -ComputerName $DC.name -Credential $Script:Credential -ErrorAction "stop"#--[ Array with all returned time data for selected DC ]--
                $HMS = (($Data.Hour).ToString().PadLeft(2,"0"))+':'+(($Data.Minute).ToString().PadLeft(2,"0"))+':'+(($Data.Second).ToString().PadLeft(2,"0"))
                If ($Console){Write-Host $HMS}
            }catch{
                $_.Exception.Message
            }
        }Else{
            #--[ local time if run from a DC ]--         
        }       
        $Script:HourResults += ($Data.Hour).ToString()
        $Script:MinuteResults += ($Data.Minute).ToString()
        $RowData += '<tr>'
        $RowData += '<td bgcolor='+$BGColor+'><font color='+$FGColor+'>'+$Data.PSComputerName+'</td>'
        $RowData += '<td bgcolor='+$BGColor+'><font color='+$FGColor+'>'+$HMS+'</td>'
      $RowData += '</tr>'
    }
    $Script:RunSummary += $RowData
}


Function CheckHour {

        If (($Script:HourResults | Sort-Object | Get-Unique).count -gt 1){
        #If (($Script:Results[0]).Hour -eq ($Script:Results[1]).Hour -eq ($Script:Results[2]).Hour -eq ($Script:Results[3]).Hour){
            If ($Console){Write-Host "-- Hour mis-match" -ForegroundColor red}
            #If ($Console){Write-Host  ($Script:Results[0])[1]"  "($Script:Results[1])[1]"   "($Script:Results[1])[1]"   "($Script:Results[1])[1]}
            $Script:HError       
    }Else{       
        If ($Console){Write-Host "-- Hour match" -ForegroundColor green}
        $Script:HError = $False
    }
}

Function CheckMinute {
    If (($Script:MinuteResults | Sort-Object | Get-Unique).count -gt 1){
        If ($Console){Write-Host "-- Minute mis-match" -ForegroundColor red}
        $Script:MError = $True
    }Else{
        If ($Console){Write-Host "-- Minute match" -ForegroundColor green}
        $Script:MError = $False
    }  
}

#--[ Main Loop ]-----------------------------------------------------

#$Script:DcList = Get-ADGroupMember 'Domain Controllers' -Credential $Script:Credential
$Script:DcList = Get-ADDomainController -Credential $Script:Credential -Filter *

While(($Script:HError) -or ($Script:MError) -or ($Script:LoopCount -eq 1)){
    If ($Console -and ($Script:LoopCount -gt 1)){Write-Host "`nLooping..." -ForegroundColor yellow}
    Write-Host "`n--[ Loop Iteration: $Script:LoopCount ]--------------------------------"
    GetTimes 
    If ($Console){Write-Host "`nComparing..." -ForegroundColor Yellow}
    CheckHour
    CheckMinute

    If(($Script:HError) -or ($Script:MError)){
        $SleepSec = 6
        If ($Console){Write-Host "`nLooping..." -ForegroundColor yellow}
        If ($Console){Write-Host "-- Sleeping $SleepSec sec..." -ForegroundColor cyan
        Sleep -Seconds $SleepSec
    }   
    $Script:LoopCount++
    If (($Script:LoopCount % 11) -eq 0){    #--[ Send email every 10 loops (counter starts at 1) ]--
        $Script:ReportBody +=$Script:RunSummary
        $Script:ReportBody += '<tr class="noBorder"><td colspan=2><font size=2 color=#909090>Script "'+$MyInvocation.MyCommand.Name+'" executed from server "'+$env:computername+'".</td></tr>'
        $Script:ReportBody += '</table><br><br>'
        eMail
    }
}

If ((!$Script:HError) -and (!$Script:MError)){
    If ($Console){Write-Host "`n-- Good Result. No further action required." -ForegroundColor green
    If ($Console){Write-Host "`n--- COMPLETED ---`n" -ForegroundColor red}
}


<#--[ Sample Config file ]--------------------------------------------------------------------
<!-- Settings & Configuration File -->
<Settings>
      <General>
            <DebugTarget>testpc</DebugTarget>
      </General>
      <Email>
            <From>PowerShell@domain.com</From>
            <To>you@domain.com</To>
            <Debug>you@domain.com</Debug>
            <Subject>Domain Controller Time Sync Error</Subject>
            <HTML>$true</HTML>
            <SmtpServer>10.10.10.50</SmtpServer>
      </Email>
      <Credentials>
            <UserName>domain\serviceaccount</UserName>
            <Password>764A0AGEAMAAwf0423413b16050a5345MgBA0AGEAMAAw0a5AWQB6AHoFEAPQA9AHA0AGEAMAAwAZgA3ADIAYQAwADYAZAADQAZgBiAGMAYQBA0AGEAMAAwQAzAAeQA0AEcAaAB1AGYANAAyADUAYQA2AGQAZAA2ADQAYwBkAA0ADEANgBiADAANwBkADEANAA4AGQA3AGUAZgBkAGYAZAA=</Password>
            <Key>kdh/AWnHbuC+Eyj2CvLO6/AWnHbuTh7HCvLOIObie8mE=</Key>
      </Credentials>
</Settings>


#>