Showing posts with label server. Show all posts
Showing posts with label server. Show all posts

Tuesday, 22 October 2019

Powershell script to find scheduled tasks on all servers or computers in the domain.

 

First off lets get all the set up variables out of the way.  A lot of these are the same variables I use in every script and I just copy them in each time so you may not want to use them all.

 

 

$Transpath = $env:LOCALAPPDATA + "\Cloudwyse\Logs\scheduled_task_Report_" + $(get-date -Format ddMMyy_HHmmss) + ".log"

Start-Transcript -Path $TransPath -NoClobber

$DateTime = (Get-Date).ToString('ddMMyy_HHmmss')

$ResultsPath = "C:\Cloudwyse\Scripts\Output\Scheduled_Task_Test_Output_" + $DateTime + ".csv"

$Date = Get-Date -Format "dd-MM-yyyy"

$Pass = cat C:\mysecurestring.txt | convertto-securestring

$Cred = new-object -typename System.Management.Automation.PSCredential -argumentlist "CONTOSO\rick.sanchez",$Pass

$DC = "DC01.contoso.com"

$TaskReport = @()

$TestedServers = 0

$OutputPath = "C:\Cloudwyse\Scripts\Output"

$SplitSeparator = "\"

$SplitOption = [System.StringSplitOptions]::RemoveEmptyEntries

  

I like to use Write-Output to add the actions to the logfile (transcript) started in the previous section.  I use this instead of comments as it does the same job but also makes reading the logs easier.  I also prefer it to Write-Host since the latter is considered bad practise.

 

First we’re just going to make sure that the folder required for the logs already exists, and create it if not.

 

 

 

Write-Output "Script started at $DateTime"

Write-Output "Checking whether report destination patch exists..."

 

if (!(Test-Path $OutputPath)) {

    Write-Output "$OutputPath does not exist, creating it now..."

    New-Item -ItemType Directory -Force -Path $OutputPath

    } else {

    Write-Output "$OutputPath already exists, continuing with script..."

    }

 

 

  

Next make a connection to the DC (I prefer doing this than running scripts on the DC itself.  Once this is done, run the LDAP query below to get all the servers in our environment.

 

 

Write-Output "Establishing powershell session with $DC"

$TargetSession = New-PSSession -ComputerName $DC -Credential $Cred

Invoke-Command $TargetSession -Scriptblock {Import-Module ActiveDirectory}

Import-PSSession $TargetSession -Module ActiveDirectory | out-null

 

$serverlist = (Get-ADComputer -LDAPFilter "(&(objectcategory=computer)(OperatingSystem=*server*))").Name

Write-Output "Server list is as follows: `r $serverlist"

Write-Output "Querying $($serverlist.count) servers that were found with the LDAP Query"

 

 

  

Then we get into our foreach loop that is going to check through every server in the list.  I’ve added a variable I’m calling $Skip.  This jut allows me to speed of the execution of the script by skipping any servers that I know are going to fail.  So I use Try Catch to test that I can access the path to my scheduled tasks.  I’ve already trapped the error I need for unauthorised access and have it in my catch statement.  If this error is triggered then the $Skip flag will be set to avoid wasting time on that record.

 

 

foreach ($server in $serverlist) {

    $Skip = $False

    $ServerFQDN = $Server + ".contoso.com"

    Write-Output "Checking server $serverFQDN"

    $serverpath = "\\" + $serverFQDN + "\c$\Windows\System32\Tasks"

    Try     {

        Write-Output "Testing $ServerPath"

        $PathTest = Test-Path $ServerPath -ErrorAction Stop

            }

    Catch [System.UnauthorizedAccessException]  {

        Write-Output "Access to $ServerPath was denied.  Setting skip flag for $ServerFQDN..."

        $Skip = $True

            }

    if (!$Skip) {

        if ($PathTest -match "False") {

            Write-Output "Server not found, setting skip flag for $ServerFQDN..."

            $Skip = $True

                }

            }

 

  

The next step will only run if the $Skip flag is not set.  A list of tasks will be pulled together from the scheduled tasks library.  

 

 

    if (!$Skip) {

        $tasks = Get-ChildItem -Path $serverpath -File

        Write-Output "Tasks for $serverFQDN as follows: `r $tasks"

        $TestedServers = $TestedServers +1

        if ($tasks) {

            $TestedTasks = 0

            Write-Output "Script has found $($tasks.count) scheduled tasks for $serverFQDN"

 

  

The script now works through each task in the variable and gets the content.  If the task is not a system task it will be added to the hash table I’m using to generate the final list which will be exported using export-csv.  I’ve recently changed the way I build these hash tables as I realised I was using an outdated method from Powershell V1 days previously.  There’s a great article on the subject here.  

 

            foreach ($task in $tasks) {

                $TaskPath = $serverpath + "\" + $task.Name

                $task = [xml] (Get-Content $TaskPath)

                [STRING]$check = $task.Task.Principals.Principal.UserId

                $SplitTaskPath = $TaskPath.split($SplitSeparator,$SplitOption)

 

                if ($task.Task.Principals.Principal.UserId) {

                    $hash = @{

                    Server      =   $ServerFQDN

                    TaskName    =   $SplitTaskPath[(($SplitTaskPath.count) - 1)]

                    Command     =   $Task.task.actions.exec.command

                    Owner       =   $task.Task.Principals.Principal.UserId

                    }

                    $Build = New-Object PSObject -Property $hash

                    

                    Write-Output "Adding a task to the list for $serverFQDN"

                    $TaskReport += $Build

                    $TestedTasks = $TestedTasks +1

                    }

                Write-Output "Added $TestedTasks of $($tasks.count) tasks to list for server $serverFQDN"

                }

        } else {

            Write-Output "No tasks found for server $serverFQDN"

               }

    Write-Output "All tests complete for server $server. $TestedServers out of $($serverlist.count) servers tested so far..."

    } else {

    $TestedServers = $TestedServers +1

    Write-Output "Skipping server $ServerFQDN. $TestedServers out of $($serverlist.count) servers tested so far..."

    }

}

 

  

Finally the script exports the results to the path created earlier and cleans up after itself.  

 

 

Write-Output "Script has tested $TestedServers servers..."

Write-Output "Writing results to $ResultsPath"

$TaskReport | Export-CSV $ResultsPath

Write-Output "Removing Powershell session for $DC"

Remove-PSSession $TargetSession

Write-Output "Script complete... Goodbye! :)"

Stop-Transcript

 

  

If you found the script helpful please leave a comment below or add a link to this article. Likewise if you notice any mistakes please share your experience.  The entire script is available below.  Good luck!  

 

 

Tuesday, 10 July 2018

Set O365 Password to never expire for just one user

 

 

Recently I needed to do this for our PRTG alerting account which was failing to send notifications as the O365 password had expired.  I did this from Powershell within Windows 10 as follows:

Launch powershell as Administrator then run

 

Install-Module MsOnline

 

 

Then run

 

Connect-MsOlService

 

 

at this point an O365 authentication box pops up - enter your credentials. Once connected run:

 

Set-MsolUser -UserPrincipalName user@contoso.com -PasswordNeverExpires $true

 

 

Some of these commands have since been deprecated. For an explanation look at this post.

 

 

Wednesday, 4 July 2018

Powershell script to display message box to user giving them the option to restart now or later

 

 

I required a script that would run automatically for a user from a RunOnce key.  This powershell script gives the user a message box asking if they would like to restart now or later.  If they choose "yes" it will reboot now, if they choose "No" or "Cancel" it will not restart but will give the user a message box telling them that they need to restart manually ASAP.

 

 

Add-Type -AssemblyName PresentationCore,PresentationFramework

$ButtonType = [System.Windows.MessageBoxButton]::YesNoCancel

$MessageIcon = [System.Windows.MessageBoxImage]::Exclamation

$MessageBody = "In order to complete setup, Windows needs to restart.  Click Yes to restart now or No if you plan to restart later."

$MessageTitle = "Cloudwyse Set-up Completion"

$ButtonType2 = [System.Windows.MessageBoxButton]::OK

$MessageIcon2 = [System.Windows.MessageBoxImage]::Error

$MessageBody2 = "The system will not operate correctly until a restart is completed.  Remember to restart ASAP!"

$MessageTitle2 = "WARNING!!"

$Choice = [System.Windows.MessageBox]::Show($MessageBody,$MessageTitle,$ButtonType,$MessageIcon)

 

If ($Choice -eq "No" -OR $Choice -eq "Cancel") {

  [System.Windows.MessageBox]::Show($MessageBody2,$MessageTitle2,$ButtonType2,$MessageIcon2)

  }  Else {

  Restart-Computer

}