Tuesday, June 11, 2019

Monitor Changes in a Folder

I receive a daily email from Powershell.com (www.powershell.com).  When I saw this script I said to myself, "There were times I really could have used this.".  Particularly when I wanted to know what files were affected when running an update.  I saved this file as Run-fileWatcher.ps1:


In this example, I created a folder called Test_Folder


# Change the $folder variable to the folder you want to monitor
$folder = "C:\Test_Folder"
$filter = '*'  # looks for all changes


 try
{
   $fsw = New-Object System.IO.FileSystemWatcher $folder , $filter -ErrorAction Stop # the FileSystemWatcher component watches for changes in the LastWrite and LastAccess properties of a file.
}


catch [System.ArgumentException] # checks for errors
{
   Write-Warning "Oops: $_"
   return
}

$fsw.IncludeSubdirectories = $true
$fsw.NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'

do
{
   $result = $fsw.WaitForChanged([ System.IO.WatcherChangeTypes]::All, 1000)
   if ($result.TimedOut) { continue }
 
   $result


   Write-Host "Change in $($result.Name) - $( $result.ChangeType)"

} while ($true)


While the script was running, I created a file called Test.txt.  Inside the file, I entered "This is a test."  I saved the file to c:\test_folder, and the output was:



When I deleted the file, the output was:



It should be possible to write the output to a file, but I haven't tested that yet.  I will put that on my list, as well as adding modification time and date.


I hope you found this helpful.  Again, go to www.powershell.com and sign up for their email.  Some of their scripts I use regularly.


Later,
Mike E



Tuesday, June 4, 2019

Finding Items in Group Policies

I have had occasion to look for specific information within a client's group policies.  In particular, what drives are being mapped for a group of users.  This client a quite a few organizational units (OUs) and, thus, quite a few groups policies (GPOs).  To simplify this process, I looked for a Powershell solution to help me.  This is what I found:

Param
    (
        # This section is the -StringToFind parameter
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [String]
        $StringToFind

    )

    Begin
    {
    $GPOsToCheck = get-gpo -all |Sort-Object -property displayname # gather all GPO information and sort by displayname
    Write-Host " Checking through" $GPOsToCheck.count "GPO's"
    }
    Process
    {
   

$ListOFAffectedGPOs = @()
$count = 1
$GPOsToCheckCount = $GPOsToCheck.count
foreach ($item in $GPOsToCheck) # go through the list of group policies
{
$Result = Get-GPOReport -name $item.DisplayName -ReportType XML   

if ($Result -match $StringToFind) # check if Result variable information matches the string
{
$ListOFAffectedGPOs += $item.DisplayName
}
else
{

}
Write-Host "$count of $GPOsToCheckCount"
$count++ 
}
Write-Host "List of GPO's that contain $StringToFind"  -ForegroundColor Green
$ListOFAffectedGPOs


    }
    End
    {
    }




The syntax of the script is:
Get-GPOThatContains.ps1 -StringToFind password

Here is the output based on my home AD domain:
PS C:\scripts> .\Get-GPOsThatContain.ps1 -StringToFind password
 Checking through 9 GPO's
1 of 9
2 of 9
3 of 9
4 of 9
5 of 9
6 of 9
7 of 9
8 of 9
9 of 9
List of GPO's that contain password
Default Domain Policy
testdest
TestSource
Windows 7 Screen Lock

The script finds all GPOs, evaluates each policy for the string to find (in this case 'password'), and lists the policies that have that string.


I have found this script very useful when we need to quickly find a GPO entry or when onboarding a new client.


I hope you have found this helpful.  Please let me know if you have any questions.


Mike


Sunday, May 26, 2019

Add Entry to Windows Event Logs

When I have created scripts, that are to used in Production, I put in code that will write events to a specific Event Log so, in the event of a failure, I can use my events as a starting point for resolving the issue.

Writing your own events is relatively easy.  As an example, let's say I have a process that should be running 24x7.  The first thing to do is to look for the process:
$process = get-process MyProcess -ErrorAction SilentlyContinue
The '-ErrorAction SilentlyContinue' is needed because the get-process code would fail if the process isn't running.


The next step is to make the appropriate event log available to add events:
New-EventLog -LogName Application -Source "My Process Code"
The 'Log-Name' parameter needs to have the correct event log.  In this example, we want to add the events to the Application log
The '-Source' parameter is used to give name/label to the event.


At this point, we have the following code for the script:
$process = get-process MyProcess -ErrorAction SilentlyContinue
New-EventLog - LogName Application -Source "My Process Code"


Now that we have information about the process, and have the event log ready, we need to evaluate the $process variable. First, let's check to see if the $process was running:
if($process) {

     Write-EventLog -LogName Application -Source "My Process Code" -EntryType                             information -EventID 3000 -Message "My Process is running"
}
This line of code states that IF $process is true (because there is information in the variable), then write a event into the Application log, the source is My Process Code, the entry type is Information, give the event ID as 3000, and the message is the process is running.


Now, what if $process is empty, meaning the process was not running?  We add and Else statement to handle this situation:
Else {
      Write-EventLog -LogName Application -Source "My Process Code" -EntryType Error -EventID 3001 Message "My Process is not running"
}
As you can see, only change we made were the entry type, the event ID, and the message.


In my scripts, I will add a line, in the Else code, that restarts the process.  So, it would look like this:

Else {
      Write-EventLog -LogName Application -Source "My Process Code" -EntryType Error -EventID 3001 Message "My Process is not running"
      Invoke-expression "C:\Applications\MyProcess.exe"
}


Here is what the complete script will look like:
$process = get-process MyProcess -ErrorAction SilentlyContinue
New-EventLog - LogName Application -Source "My Process Code"


if($process) {

     Write-EventLog -LogName Application -Source "My Process Code" -EntryType                             information -EventID 3000 -Message "My Process is running"

}

Else {
      Write-EventLog -LogName Application -Source "My Process Code" -EntryType Error -EventID 3001 Message "My Process is not running"
      Invoke-expression "C:\Applications\MyProcess.exe"
}
I hope you find this article helpful.  Please feel free to contact me if you have any questions.


Mike


Wednesday, May 22, 2019

I'm coming back

Greetings everyone!

After a lengthy hiatus, I will be coming back with some cool scripts I have been using over the last 14 months.

So, stay tuned!

Mike