diff --git a/CHANGELOG.md b/CHANGELOG.md index da49734..52a9d80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,19 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## 1.6.0 - 2019.04.09 + +### Added + +- Aliases `Count`, `CountOnly` for parameter `Minimal`, +- Export results to JSON file, parameter `ExportJSON` and `ExportJSONpath`, +- Search for the exact user name, parameter `Strict`. + +### Changed + +- Clearing and formatting the code, +- Minor changes. + ## 1.5.3 - 2019.04.09 ### Changed diff --git a/Find-ServiceUser.ps1 b/Find-ServiceUser.ps1 index 3595d3c..94167f0 100644 --- a/Find-ServiceUser.ps1 +++ b/Find-ServiceUser.ps1 @@ -1,40 +1,42 @@ Function Find-ServiceUser { - [CmdletBinding()] - param ( - [parameter(mandatory=$true,position=0)] - [string[]] - $computer, + [CmdletBinding()] + param ( + [parameter(mandatory = $true, position = 0)] + [string[]] + $computer, - [parameter(mandatory=$false,position=1)] - [string] - $user - ) - $user = $user.trim() - $computer=$computer.trim() - if ([bool](Test-Connection -ComputerName $computer -Count 1 -ErrorAction SilentlyContinue)){ - $filter = "startname like '%$($user)%'" - Write-Verbose -Message "WMI query for system services." - try { - $service_ = Get-CimInstance -classname win32_service -filter "$filter" -ComputerName $computer -ErrorAction Stop - } - catch { - Write-Error -Message "Failed WMI query for system services with Service Logon Account as ""$user"": $_" + [parameter(mandatory = $false, position = 1)] + [string] + $user, + + [parameter(Mandatory = $false, HelpMessage = 'Turns on the search after the exact username.')] + [switch] + $Strict + ) + $user = $user.trim() + $computer = $computer.trim() + if ([bool](Test-Connection -ComputerName $computer -Count 1 -ErrorAction SilentlyContinue)) { + if ($Strict) { + $filter = "startname = '$($user)'" + #Write-Information $filter -InformationAction Continue + } else { + $filter = "startname LIKE '%$($user)%'" + } + Write-Verbose -Message "WMI query for system services." + try { + $service_ = Get-CimInstance -classname win32_service -filter "$filter" -ComputerName $computer -ErrorAction Stop + } + catch { + Write-Error -Message "Failed WMI query for system services with Service Logon Account as ""$user"": $_" + } + if ($service_) { + Write-Verbose -Message "Return WMI query data" + return $service_ + } + } + else { + Write-Verbose -Message "$computer`: Connection failed!" + Write-Information -MessageData "$computer`: Connection failed!" -InformationAction Continue + return $null } - if ($service_) { - Write-Verbose -Message "Return WMI query data" - return $service_ - #New-Object -TypeName psobject -Property @{` - #Server = $service_.Systemname; - #Servicename = $service_.Name; - #ServicePath = $service_.Pathname; - #ServiceDisplayName = $service_.Displayname; - #StartUser = $service_.Startname; - #ServiceState = $service_.state - #} - } - } else { - Write-verbose -Message "$computer`: Connection failed!" - Write-Information -MessageData "$computer`: Connection failed!" -InformationAction Continue - return $null - } }# end function Find-ServiceUser diff --git a/Find-TaskServiceUser.ps1 b/Find-TaskServiceUser.ps1 index 9d35b2d..6df1f63 100644 --- a/Find-TaskServiceUser.ps1 +++ b/Find-TaskServiceUser.ps1 @@ -1,5 +1,5 @@ Function Find-TaskServiceUser { -<# + <# .SYNOPSIS Finding scheduled tasks, system services on computer by user name. .DESCRIPTION @@ -17,7 +17,7 @@ A Switch to look for system services where user name is matched. .PARAMETER Minimal A switch to enable minimalistic results. Object containing the computer name, number of tasks and/or number of services only. With -Log information about log file path is displayed but log file is not minimal. The return value is en object. .PARAMETER Export -Enable exporting results objects to file (using "Export-Clixml"). Export file path is defined in "Exportpath" parameter. +Enable exporting results objectsr to file (using "Export-Clixml"). Export file path is defined in "Exportpath" parameter. .PARAMETER Exportpath File name path to export results finding scheduled tasks and/or system services. .PARAMETER Log @@ -60,196 +60,224 @@ https://www.powershellgallery.com/packages/Find-TaskServiceUser ICON CREDITS: Module icon made by [Freepik](https://www.freepik.com/) from [Flaticon](https://www.flaticon.com/) is licensed [CC 3.0 BY](http://creativecommons.org/licenses/by/3.0/) DONATION: If you want to support my work https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=ZQJXFYKHL7JUA¤cy_code=PLN&source=url #> - [CmdletBinding()] - Param( - [parameter(mandatory=$false, position=0, valuefrompipeline = $true, ValueFromPipelineByPropertyName=$true, HelpMessage='Computer NetBIOS, DNS name or IP.')] - [Alias('MachineName','Server')] - [string[]]$Computer=$env:COMPUTERNAME, + [CmdletBinding()] + Param( + [parameter(mandatory = $false, position = 0, valuefrompipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = 'Computer NetBIOS, DNS name or IP.')] + [Alias('MachineName', 'Server')] + [string[]]$Computer = $env:COMPUTERNAME, - [parameter(Mandatory=$false, HelpMessage='User(s) or group name(s) to find scheduled tasks and/or services. Group is used for the security context of the scheduled task only, not system services.')] - [string[]]$User='Administrator', + [parameter(Mandatory = $false, HelpMessage = 'User(s) or group name(s) to find scheduled tasks and/or services. Group is used for the security context of the scheduled task only, not system services.')] + [string[]]$User = 'Administrator', - [parameter(Mandatory=$false, HelpMessage='Switch to find system services.')] - [switch]$Service, + [parameter(Mandatory = $false, HelpMessage = 'Turns on the search after the exact username.')] + [switch]$Strict, - [parameter(Mandatory=$false, HelpMessage='Switch to find scheduled tasks.')] - [switch]$Task, + [parameter(Mandatory = $false, HelpMessage = 'Switch to find system services.')] + [switch]$Service, - [parameter(Mandatory=$false, HelpMessage='Minimalistic results. Object containing the computer name, number of tasks and/or number of services only. with -Log info about log file is displayed but log file is not minimal.')] - [switch]$Minimal, + [parameter(Mandatory = $false, HelpMessage = 'Switch to find scheduled tasks.')] + [switch]$Task, - [parameter(Mandatory=$false, HelpMessage= 'Enable exporting to file.')] - [switch]$Export, + [parameter(Mandatory = $false, HelpMessage = 'Minimalistic results. Object containing the computer name, number of tasks and/or number of services only. with -Log info about log file is displayed but log file is not minimal.')] + [Alias('Count','CountOnly')] + [switch]$Minimal, - [parameter(Mandatory=$false, HelpMessage= 'Enter path to export file.')] - [string]$Exportpath = [Environment]::GetFolderPath("MyDocuments")+"\Find-TaskServiceUser.XML", + [parameter(Mandatory = $false, HelpMessage = 'Enable exporting to file.')] + [switch]$Export, - [parameter(Mandatory=$false, HelpMessage='Switch to enable logging.')] - [switch]$Log, + [parameter(Mandatory = $false, HelpMessage = 'Enter path to export file.')] + [string]$Exportpath = [Environment]::GetFolderPath("MyDocuments") + "\Find-TaskServiceUser.XML", - [parameter(Mandatory=$false, HelpMessage='Log file path. Default is ''[$env:TEMP]\Find-TaskServiceUser.log''.')] - [string]$Logfile="$env:TEMP\Find-TaskServiceUser.log" - ) - Begin { - if (!$service -and !$task) { - $Service = $Task = $true - } -# Write-output "You must provide 'service' or/and 'task' parameter`n" -# Write-output 'Examples:' -# Write-output ' Find-TaskServiceUser -Computer "WSRV00" -User "BobbyK" -Service -Task' -# Write-output ' Find-TaskServiceUser -Computer "WSRV01" -User "BobbyK" -Task -Log' -# Write-output ' "WSRV00","WSRV03" | Find-TaskServiceUser -Service -Task' -# Write-output ' "WSRV04" | Find-TaskServiceUser -Service' -# Write-output ' $object = Find-TaskServiceUser -Service -Task -Computer "WSRV04" -User "SYSTEM" -Minimal' - if (-not $Minimal) { - if ($user -eq "Administrator") { - Write-Output "Set default user: Administrator" - } - if ($computer -eq $env:COMPUTERNAME) { - Write-output "Set default computer: $env:COMPUTERNAME (localhost)" - } - } else { - Write-Verbose "Initializing minimalistic results." - $minimal_obj = @() - $s=0 - $t=0 - $services_count = $s - $tasks_count = $t - } - if ($Log) { - Write-Log "---------$(get-date)---------" - } - $i=1 #write-progress - } # end BEGIN block - Process { - foreach ($user_item in $User) { - $user_item = $user_item.trim() - write-progress -id 1 -activity "Searching user" -status "$user_item" -percentComplete ($i++ / $user.Count * 100) - $j=1 #write-progress - foreach ($item in $Computer) { - $item = $item.trim() - write-progress -parentId 1 -activity "Searching on server" -status "$item" -percentComplete ($j++ / $Computer.count * 100) - #Tasks - if ($task) { - if (!$Minimal) { - Write-output "Finding tasks with user: ""$($user_item.toupper())"" on machine: ""$($item.toupper())""" - } - if ($Log) { - Write-Log "$(get-date): Finding tasks with user: ""$($user_item.toupper())"" on machine: ""$($item.toupper())""" - } - $tasks = Find-TaskUser -server $item -user $user_item | Sort-Object taskname - #$tasks - if ($tasks) { - # tasks found - Write-Verbose "Task result not null" - if ($Log) { - Write-Log "$(get-date): Scheduled tasks:" - } - $tasksdata = $tasks | Select-Object Hostname, Taskname, Author, "Run as user", URI - if ($Minimal) { - $tasks_count = ($tasks | Measure-Object).count - } else { - Write-output "Found scheduled task(s) where ""$user_item"" matches task author or 'run as user'" - $tasksdata | Format-Table -AutoSize - } - if ($Log) { - $tasksdata | ForEach-Object { Write-Log $_ } - } - } else { - # tasks not found - if ($Log) { - Write-Log "$(get-date): No scheduled tasks or no data from ""$item"" for user ""$user_item""" - } - if ($Minimal) { - $tasks_count = $t - } else { - Write-output "No scheduled tasks or no data from ""$item"" for user ""$user_item""" + [parameter(Mandatory = $false, HelpMessage = 'Enable exporting to JSON file.')] + [switch]$ExportJSON, + + [parameter(Mandatory = $false, HelpMessage = 'Enter path to export JSON file.')] + [string]$ExportJSONpath = [Environment]::GetFolderPath("MyDocuments") + "\Find-TaskServiceUser.json", + + [parameter(Mandatory = $false, HelpMessage = 'Switch to enable logging.')] + [switch]$Log, + + [parameter(Mandatory = $false, HelpMessage = 'Log file path. Default is ''[$env:TEMP]\Find-TaskServiceUser.log''.')] + [string]$Logfile = "$env:TEMP\Find-TaskServiceUser.log" + ) + Begin { + if (!$service -and !$task) { + $Service = $Task = $true + } + if (-not $Minimal) { + if ($user -eq "Administrator") { + Write-Output "Set default user: Administrator" } - } + if ($computer -eq $env:COMPUTERNAME) { + Write-Output "Set default computer: $env:COMPUTERNAME (localhost)" + } } - #Services - if ($service) { - if (-not $Minimal) { - Write-output "Finding system services with user: ""$($user_item.toupper())"" on machine: ""$($item.toupper())""" - } - if ($Log) { - Write-Log "$(get-date): Finding services with user: ""$($user_item.toupper())"" on machine: ""$($item.toupper())""" - } - $services = Find-ServiceUser -computer $item -user $user_item | Sort-Object name - if ($services) { - # services found - Write-Verbose "Services result not null" - if ($Log) { - Write-Log "$(get-date): System services:" - } - $output1 = $services | select-object SystemName,Name, StartName,State - if ($Minimal) { - $services_count = ($services | Measure-Object).count - } else { - Write-output "Found system service(s) where ""$user_item"" matches 'Service Logon Account'" - $output1 | Format-Table -AutoSize - } - if ($Log) { - $output1 | ForEach-Object { Write-Log $_ } - } - } else { - # services not found - Write-Verbose "Services result is null" - if ($Log) { - Write-Log "$(get-date): No services found or no data from ""$item"" for user ""$user_item""" - } - if ($Minimal) { - $services_count = $s - } else { - Write-output "No system services or no data from ""$item"" for user ""$user_item""" - } - } + else { + Write-Verbose "Initializing minimalistic results." + $minimal_obj = @() + $s = 0 + $t = 0 + $services_count = $s + $tasks_count = $t + } + if ($Log) { + Write-Log "---------$(Get-Date)---------" + } + $i = 1 #write-progress + } # end BEGIN block + Process { + foreach ($user_item in $User) { + $user_item = $user_item.trim() + Write-Progress -id 1 -activity "Searching user" -status "$user_item" -percentComplete ($i++ / $user.Count * 100) + $j = 1 #write-progress + foreach ($item in $Computer) { + $item = $item.trim() + Write-Progress -parentId 1 -activity "Searching on server" -status "$item" -percentComplete ($j++ / $Computer.count * 100) + #Tasks + if ($task) { + if (!$Minimal) { + Write-Output "Finding tasks with user: ""$($user_item.toupper())"" on machine: ""$($item.toupper())""" + } + if ($Log) { + Write-Log "$(Get-Date): Finding tasks with user: ""$($user_item.toupper())"" on machine: ""$($item.toupper())""" + } + if ($Strict) { + $tasks = Find-TaskUser -server $item -user $user_item -Strict | Sort-Object taskname + } else { + $tasks = Find-TaskUser -server $item -user $user_item | Sort-Object taskname + } + #$tasks + if ($tasks) { + # tasks found + Write-Verbose "Task result not null" + if ($Log) { + Write-Log "$(Get-Date): Scheduled tasks:" + } + $tasksdata = $tasks | Select-Object Hostname, Taskname, Author, "Run as user", URI + if ($Minimal) { + $tasks_count = ($tasks | Measure-Object).count + } + else { + Write-Output "Found scheduled task(s) where ""$user_item"" matches task author or 'run as user'" + $tasksdata | Format-Table -AutoSize + } + if ($Log) { + $tasksdata | ForEach-Object { Write-Log $_ } + } + } + else { + # tasks not found + if ($Log) { + Write-Log "$(Get-Date): No scheduled tasks or no data from ""$item"" for user ""$user_item""" + } + if ($Minimal) { + $tasks_count = $t + } + else { + Write-Output "No scheduled tasks or no data from ""$item"" for user ""$user_item""" + } + } + } + #Services + if ($service) { + if (-not $Minimal) { + Write-Output "Finding system services with user: ""$($user_item.toupper())"" on machine: ""$($item.toupper())""" + } + if ($Log) { + Write-Log "$(Get-Date): Finding services with user: ""$($user_item.toupper())"" on machine: ""$($item.toupper())""" + } + if ($Strict){ + $services = Find-ServiceUser -computer $item -user $user_item -strict | Sort-Object name + } else { + $services = Find-ServiceUser -computer $item -user $user_item | Sort-Object name + } + if ($services) { + # services found + Write-Verbose "Services result not null" + if ($Log) { + Write-Log "$(Get-Date): System services:" + } + $output1 = $services | Select-Object SystemName, Name, StartName, State + if ($Minimal) { + $services_count = ($services | Measure-Object).count + } + else { + Write-Output "Found system service(s) where ""$user_item"" matches 'Service Logon Account'" + $output1 | Format-Table -AutoSize + } + if ($Log) { + $output1 | ForEach-Object { Write-Log $_ } + } + } + else { + # services not found + Write-Verbose "Services result is null" + if ($Log) { + Write-Log "$(Get-Date): No services found or no data from ""$item"" for user ""$user_item""" + } + if ($Minimal) { + $services_count = $s + } + else { + Write-Output "No system services or no data from ""$item"" for user ""$user_item""" + } + } + } + if (-not $tasks -and (-not $task -and $service)) { + $tasks_count = $null + } + if (-not $services -and (-not $service -and $task)) { + $services_count = $null + } + if ($Minimal) { + $minimal_obj += [PSCustomObject]@{ + UserName = $user_item + ComputerName = $item + ServicesCount = $services_count + TasksCount = $tasks_count + } + $services_count = $s + $tasks_count = $t + } + if ($Export -or $ExportJSON) { + Write-Verbose -Message "Building objects with all results" + if ($tasks) { + $tasks_all += $tasks + } + if ($services) { + $services_all += $services + } + } + } # end foreach $Computer + } # end foreach $User + } # end PROCESS block + End { + if ($Log -and -not $Minimal) { + Write-Output "Log File: $($Logfile)" } - if (-not $tasks -and (-not $task -and $service)) { - $tasks_count = $null + elseif ($minimal -and $Log) { + Write-Information -MessageData "Log File: $($Logfile)" -InformationAction Continue + $minimal_obj } - if (-not $services -and (-not $service -and $task)) { - $services_count = $null + elseif ($minimal -and -not $log) { + $minimal_obj } - if ($Minimal) { - $minimal_obj += [PSCustomObject]@{ - UserName = $user_item - ComputerName = $item - ServicesCount = $services_count - TasksCount = $tasks_count - } - $services_count = $s - $tasks_count = $t + if ($export) { + Write-Information -MessageData "Export XML File: $($Exportpath)" -InformationAction Continue + Write-Information -MessageData "Export XML File: You can import file using 'Import-Clixml `"$($Exportpath)`"'" -InformationAction Continue + $task_all_unique = $tasks_all | Sort-Object taskname -Unique + $services_all_unique = $services_all | Sort-Object name -Unique + $export_data = @{"Tasks" = $task_all_unique; "Services" = $services_all } + #Add-Content -LiteralPath $Exportpath -Value $export_data -PassThru + Export-Clixml -LiteralPath $Exportpath -InputObject $export_data } - if ($Export) { - Write-Verbose -Message "Building objects with all results" - if ($tasks) { - $tasks_all += $tasks - } - if ($services) { - $services_all += $services - } + if ($ExportJSON) { + Write-Information -MessageData "Export JSON File: $($Exportjsonpath)" -InformationAction Continue + Write-Information -MessageData "Export JSON File: You can import file using '`$json_data = Get-Content -Raw -Path `"$($Exportjsonpath)`" | ConvertFrom-Json'" -InformationAction Continue + $task_all_unique = $tasks_all | Sort-Object taskname -Unique + $services_all_unique = $services_all | Sort-Object name -Unique + $export_data = @{"Tasks" = $task_all_unique; "Services" = $services_all } + $export_data | ConvertTo-Json | out-file $Exportjsonpath } - } # end foreach $Computer - } # end foreach $User - } # end PROCESS block - End { - if ($Log -and -not $Minimal) { - Write-output "Log File: $($Logfile)" - } elseif($minimal -and $Log) { - Write-Information -MessageData "Log File: $($Logfile)" -InformationAction Continue - $minimal_obj - } elseif ($minimal -and -not $log) { - $minimal_obj - } - if ($export) { - Write-Information -MessageData "Export File: $($Exportpath)" -InformationAction Continue - Write-Information -MessageData "Export File: You can import faile using 'Import-Clixml `"$($Exportpath)`"'" -InformationAction Continue - $task_all_unique = $tasks_all | sort taskname -Unique - $services_all_unique = $services_all | sort name -Unique - $export_data = @{"Tasks"=$task_all_unique;"Services"=$services_all} - #Add-Content -LiteralPath $Exportpath -Value $export_data -PassThru - Export-Clixml -LiteralPath $Exportpath -InputObject $export_data - } - } # end END block + } # end END block } # end Find-TaskServiceUser function diff --git a/Find-TaskServiceUser.psd1 b/Find-TaskServiceUser.psd1 index dd6ee90..0739d4f 100644 Binary files a/Find-TaskServiceUser.psd1 and b/Find-TaskServiceUser.psd1 differ diff --git a/Find-TaskServiceUser.psm1 b/Find-TaskServiceUser.psm1 index d407414..436bb86 100644 --- a/Find-TaskServiceUser.psm1 +++ b/Find-TaskServiceUser.psm1 @@ -1,25 +1,22 @@ -#Get files. +#Get files. $files = @( Get-ChildItem -Path $PSScriptRoot\*.ps1 -ErrorAction SilentlyContinue ) #Dot source the files -Foreach($import in @($files)) -{ - Try - { +Foreach ($import in @($files)) { + Try { . $import.fullname } - Catch - { + Catch { Write-Error -Message "Failed to import file $($import.fullname): $_" } } #check update -New-Variable -Name ModuleVersion -Value "1.5.3" +New-Variable -Name ModuleVersion -Value "1.6.0" + $url = "https://api.github.com/repos/voytas75/Find-TaskServiceUser/releases/latest" $oldProtocol = [Net.ServicePointManager]::SecurityProtocol # We switch to using TLS 1.2 because GitHub closes the connection if it uses 1.0 or 1.1 [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -try -{ +try { $response = Invoke-WebRequest -URI $url | ConvertFrom-Json if ([System.Version]$response.name -gt [System.Version]$ModuleVersion) { @@ -31,8 +28,7 @@ try Write-Information "You have the latest version ($ModuleVersion) installed." -InformationAction Continue } } -catch -{ +catch { # Github limits the number of unauthenticated API requests. To avoid this throwing an error we supress it here. Write-Information "Importing Find-TaskServiceUser version $ModuleVersion" -InformationAction Continue Write-Information "Unable to reach GitHub, please manually verify that you have the latest version by going to https://github.com/voytas75/Find-TaskServiceUser/releases/latest" -InformationAction Continue diff --git a/Find-TaskUser.ps1 b/Find-TaskUser.ps1 index 1035ef2..44210ed 100644 --- a/Find-TaskUser.ps1 +++ b/Find-TaskUser.ps1 @@ -3,39 +3,13 @@ Function Find-TaskUser { param( [string]$server, - [string]$user + [string]$user, + + [switch]$Strict ) process { $server = $server.trim() $user = $user.trim() - <# - #23 start - #if ([bool](Get-Command Get-ScheduledTask -ErrorAction SilentlyContinue)) { - if ([bool](Test-Connection -ComputerName $server -Count 1 -ErrorAction SilentlyContinue)){ - if ([bool](Invoke-Command -ComputerName $server -EnableNetworkAccess -ScriptBlock {[bool](Get-Command Get-ScheduledTask -ErrorAction SilentlyContinue)} -erroraction silentlycontinue)) { - try { - Write-Verbose -Message "$server : Try use Get-ScheduledTask" - $data = Get-ScheduledTask -CimSession $server -ErrorAction stop | Where-Object {$_.author -match $user -or $_.Principal.userid -match $user} | Select-Object @{Name="Hostname"; Expression = {$_.PSComputerName}}, taskname, @{Name="Run As User"; Expression = {$_.Principal.userid}}, Author, URI - return $data - } - catch { - Write-verbose -Message "Get-ScheduledTask error: $_" - Write-Verbose -Message "$server : Switching to schtasks command." - - Invoke-SCHTasks -server $server -user $user - - } - } else { - Invoke-SCHTasks -server $server -user $user - - } - } else { - Write-verbose -Message "$server`: Connection failed!" - Write-Information -MessageData "$server`: Connection failed!" -InformationAction Continue - return $null - } - #23 end -#> #26 start if ($server -eq $env:COMPUTERNAME -or $server -eq "localhost") { #local @@ -43,14 +17,22 @@ Function Find-TaskUser { try { Write-Verbose -Message "$server`: Try use Get-ScheduledTask." #do cimsession on local to have "pscomputername" property - return Get-ScheduledTask -CimSession $server -ErrorAction stop | Where-Object {$_.author -match $user -or $_.Principal.userid -match $user} | Select-Object @{Name="Hostname"; Expression = {$_.PSComputerName}}, taskname, @{Name="Run As User"; Expression = {$_.Principal.userid}}, Author, URI + if ($Strict) { + return Get-ScheduledTask -CimSession $server -ErrorAction stop | Where-Object { $_.author -eq $user -or $_.Principal.userid -eq $user } | Select-Object @{Name = "Hostname"; Expression = { $_.PSComputerName } }, taskname, @{Name = "Run As User"; Expression = { $_.Principal.userid } }, Author, URI + } + return Get-ScheduledTask -CimSession $server -ErrorAction stop | Where-Object { $_.author -match $user -or $_.Principal.userid -match $user } | Select-Object @{Name = "Hostname"; Expression = { $_.PSComputerName } }, taskname, @{Name = "Run As User"; Expression = { $_.Principal.userid } }, Author, URI } catch { - Write-verbose -Message "$server`: Get-ScheduledTask error: $_" + Write-Verbose -Message "$server`: Get-ScheduledTask error: $_" Write-Verbose -Message "$server`: Switching to schtasks command." - Invoke-SCHTasks -server $server -user $user + if ($Strict) { + Invoke-SCHTasks -server $server -user $user -Strict + } else { + Invoke-SCHTasks -server $server -user $user + } } - } else { + } + else { #remote Write-Verbose -Message "$server`: Remote computer." try { @@ -58,7 +40,7 @@ Function Find-TaskUser { Test-Connection -ComputerName $server -Count 1 -ErrorAction Stop | Out-Null } catch { - Write-verbose -Message "$server`: Test-Connection error: $_" + Write-Verbose -Message "$server`: Test-Connection error: $_" Write-Information -MessageData "$server Offline?" -InformationAction Continue return $null } @@ -67,7 +49,7 @@ Function Find-TaskUser { try { #check if is local get-scheduledtask Write-Verbose -Message "$server`: Is local command Get-ScheduledTask ?" - Invoke-Command -ScriptBlock {Get-Command Get-ScheduledTask -ErrorAction Stop} -ErrorAction stop | Out-Null + Invoke-Command -ScriptBlock { Get-Command Get-ScheduledTask -ErrorAction Stop } -ErrorAction stop | Out-Null } catch { # no local get-scheduledtask @@ -75,10 +57,14 @@ Function Find-TaskUser { Write-Verbose -Message "$server`: No local command Get-ScheduledTask." try { Write-Verbose -Message "$server`: Is remote command Get-ScheduledTask ?" - Invoke-Command -ComputerName $server -EnableNetworkAccess -ScriptBlock {Get-Command Get-ScheduledTask -ErrorAction stop} -ErrorAction stop | Out-Null + Invoke-Command -ComputerName $server -EnableNetworkAccess -ScriptBlock { Get-Command Get-ScheduledTask -ErrorAction stop } -ErrorAction stop | Out-Null try { Write-Verbose -Message "$server`: Try use remote command Get-ScheduledTask." - $remote_data = Invoke-Command -ComputerName $server -EnableNetworkAccess -ScriptBlock {Get-ScheduledTask -erroraction stop} -erroraction stop | Where-Object {$_.author -match $user -or $_.Principal.userid -match $user} | Select-Object @{Name="Hostname"; Expression = {$_.PSComputerName}}, taskname, @{Name="Run As User"; Expression = {$_.Principal.userid}}, Author, URI + if ($Strict) { + $remote_data = Invoke-Command -ComputerName $server -EnableNetworkAccess -ScriptBlock { Get-ScheduledTask -erroraction stop } -erroraction stop | Where-Object { $_.author -eq $user -or $_.Principal.userid -eq $user } | Select-Object @{Name = "Hostname"; Expression = { $_.PSComputerName } }, taskname, @{Name = "Run As User"; Expression = { $_.Principal.userid } }, Author, URI + } else { + $remote_data = Invoke-Command -ComputerName $server -EnableNetworkAccess -ScriptBlock { Get-ScheduledTask -erroraction stop } -erroraction stop | Where-Object { $_.author -match $user -or $_.Principal.userid -match $user } | Select-Object @{Name = "Hostname"; Expression = { $_.PSComputerName } }, taskname, @{Name = "Run As User"; Expression = { $_.Principal.userid } }, Author, URI + } #$remote_data if ($remote_data) { Write-Verbose -Message "$server`: return data from remote command Get-ScheduledTask." @@ -92,7 +78,11 @@ Function Find-TaskUser { catch { Write-Verbose -Message "$server`: Error useing remote command Get-ScheduledTask: $_" Write-Verbose -Message "$server`: Switch to SCHTASK." - $remote_schtask_data = Invoke-SCHTasks -server $server -user $user + if ($Strict) { + $remote_schtask_data = Invoke-SCHTasks -server $server -user $user -Strict + } else { + $remote_schtask_data = Invoke-SCHTasks -server $server -user $user + } return $remote_schtask_data } } @@ -107,49 +97,12 @@ Function Find-TaskUser { return $remote_schtask_data } } - #return Get-ScheduledTask -CimSession $server -ErrorAction stop | Where-Object {$_.author -match $user -or $_.Principal.userid -match $user} | Select-Object @{Name="Hostname"; Expression = {$_.PSComputerName}}, taskname, @{Name="Run As User"; Expression = {$_.Principal.userid}}, Author, URI } catch { - #Write-verbose -Message "Get-ScheduledTask error: $_" - #Write-Verbose -Message "$server`: Switching to schtasks command." - #Invoke-SCHTasks -server $server -user $user Write-Verbose -Message $_ return $null } } #26 end - - -<# - if ([bool](Get-Command Get-ScheduledTask -ErrorAction SilentlyContinue)) { - Write-Verbose -Message 'Running ''Get-ScheduleTask''' - $data = Get-ScheduledTask -CimSession $server.trim() | Where-Object {$_.author -match $user.trim() -or $_.Principal.userid -match $user.trim()} | Select-Object hostname, taskname, @{Name="Run As User"; Expression = {$_.Principal.userid}}, Author, URI - foreach ($record in $data) { - $record.hostname = $server.trim() - } - return $data - } else { - Write-Verbose -Message 'Running system command ''schtasks''' - if ($server.trim() -match $env:COMPUTERNAME -or $server.trim() -eq "localhost") { - try { - $tasks=Invoke-Expression "schtasks /query /fo csv /NH /v" -ErrorAction Stop - } - catch { - Write-Error -Message "Failed to invoke ""schtasks"": $_" - } - } else { - try { - $tasks=Invoke-Expression "schtasks /query /s $server.trim() /NH /fo csv /v" -ErrorAction Stop - } - catch { - Write-Error -Message "Failed to invoke ""schtasks"": $_" - } - } - Write-Verbose -Message 'Filtering scheduled tasks' - $header = "HostName","TaskName","Next Run Time","Status","Logon Mode","Last Run Time","Last Result","Author","Task To Run","Start In","Comment","Scheduled Task State","Idle Time","Power Management","Run As User","Delete Task If Not Rescheduled","Stop Task If Runs X Hours and X Mins","Schedule","Schedule Type","Start Time","Start Date","End Date","Days","Months","Repeat: Every","Repeat: Until: Time","Repeat: Until: Duration","Repeat: Stop If Still Running" - return $tasks | ConvertFrom-Csv -Header $header | Where-Object {$_."Run As User" -match $user -or $_."Author" -match $user}| Select-Object hostname, @{Name="taskname"; Expression = {($_.TaskName).split("\")[-1]}}, "run as user", author, @{Name="URI"; Expression = {$_.TaskName}} -Unique - } # end if -#> - } } diff --git a/Invoke-SCHTasks.ps1 b/Invoke-SCHTasks.ps1 index daca2e8..a2e4816 100644 --- a/Invoke-SCHTasks.ps1 +++ b/Invoke-SCHTasks.ps1 @@ -3,30 +3,36 @@ Function Invoke-SCHTasks { param( [string]$server, - [string]$user + [string]$user, + + [switch]$Strict ) process { -if (($server -match $env:COMPUTERNAME) -or ($server -eq "localhost")) { - Write-Verbose -Message "$server : Try use schtasks on local computer" - try { - $tasks=Invoke-Expression "schtasks /query /fo csv /v" -ErrorAction Stop - } - catch { - Write-Error -Message "Failed to invoke ""schtasks"": $_" - } -} else { - Write-Verbose -Message "$server : Try use schtasks on remote computer" - $exp_schtasks = "schtasks /Query /S $server /FO CSV /V" - write-Verbose $exp_schtasks - try { - $tasks=Invoke-Expression $exp_schtasks -ErrorAction Stop - } - catch { - Write-Error -Message "Failed to invoke ""schtasks"": $_" - } -} -Write-Verbose -Message "$server : Filtering scheduled tasks" -$header = "HostName","TaskName","Next Run Time","Status","Logon Mode","Last Run Time","Last Result","Author","Task To Run","Start In","Comment","Scheduled Task State","Idle Time","Power Management","Run As User","Delete Task If Not Rescheduled","Stop Task If Runs X Hours and X Mins","Schedule","Schedule Type","Start Time","Start Date","End Date","Days","Months","Repeat: Every","Repeat: Until: Time","Repeat: Until: Duration","Repeat: Stop If Still Running" -return $tasks | ConvertFrom-Csv -Header $header | Where-Object {$_."Run As User" -match $user -or $_."Author" -match $user}| Select-Object hostname, @{Name="taskname"; Expression = {($_.TaskName).split("\")[-1]}}, "run as user", author, @{Name="URI"; Expression = {$_.TaskName}} -Unique + if (($server -match $env:COMPUTERNAME) -or ($server -eq "localhost")) { + Write-Verbose -Message "$server : Try use schtasks on local computer" + try { + $tasks = Invoke-Expression "schtasks /query /fo csv /v" -ErrorAction Stop + } + catch { + Write-Error -Message "Failed to invoke ""schtasks"": $_" + } + } + else { + Write-Verbose -Message "$server : Try use schtasks on remote computer" + $exp_schtasks = "schtasks /Query /S $server /FO CSV /V" + Write-Verbose $exp_schtasks + try { + $tasks = Invoke-Expression $exp_schtasks -ErrorAction Stop + } + catch { + Write-Error -Message "Failed to invoke ""schtasks"": $_" + } + } + Write-Verbose -Message "$server : Filtering scheduled tasks" + $header = "HostName", "TaskName", "Next Run Time", "Status", "Logon Mode", "Last Run Time", "Last Result", "Author", "Task To Run", "Start In", "Comment", "Scheduled Task State", "Idle Time", "Power Management", "Run As User", "Delete Task If Not Rescheduled", "Stop Task If Runs X Hours and X Mins", "Schedule", "Schedule Type", "Start Time", "Start Date", "End Date", "Days", "Months", "Repeat: Every", "Repeat: Until: Time", "Repeat: Until: Duration", "Repeat: Stop If Still Running" + if ($Strict) { + return $tasks | ConvertFrom-Csv -Header $header | Where-Object { $_."Run As User" -eq $user -or $_."Author" -eq $user } | Select-Object hostname, @{Name = "taskname"; Expression = { ($_.TaskName).split("\")[-1] } }, "run as user", author, @{Name = "URI"; Expression = { $_.TaskName } } -Unique + } + return $tasks | ConvertFrom-Csv -Header $header | Where-Object { $_."Run As User" -match $user -or $_."Author" -match $user } | Select-Object hostname, @{Name = "taskname"; Expression = { ($_.TaskName).split("\")[-1] } }, "run as user", author, @{Name = "URI"; Expression = { $_.TaskName } } -Unique } } \ No newline at end of file diff --git a/README.md b/README.md index 3f4c507..d1aec48 100644 --- a/README.md +++ b/README.md @@ -24,24 +24,33 @@ Install-Module -Name Find-TaskServiceUser -Scope CurrentUser ### Examples -1. Find system services and scheduled tasks on "WSRV00" for user "BobbyK" with logging output to a file: +* Find system services and scheduled tasks on "WSRV00" for user "BobbyK" with logging output to a file: + ```powershell PS> Find-TaskServiceUser -Computer "WSRV00" -User "BobbyK" -Service -Task -Log ``` -2. Find system services and scheduled tasks on computers "WSRV01", "WSRV02" for user "Administrator": + +* Find system services and scheduled tasks on computers "WSRV01", "WSRV02" for user "Administrator": + ```powershell PS> "WSRV01","WSRV02" | Find-TaskServiceUser -Service -Task ``` -3. Find system services and scheduled tasks on computers "WSRV01", "WSRV02", "WSRV03" for user "BobbyK": + +* Find system services and scheduled tasks on computers "WSRV01", "WSRV02", "WSRV03" for user "BobbyK": + ```powershell PS> @("WSRV01","WSRV02"), "WSRV03" | Find-TaskServiceUser -Task -User "BobbyK" ``` -4. Find tasks and services on server "WSRV04" for "SYSTEM" user and return a minimalistic result as custom object `$data`: + +* Find tasks and services on server "WSRV04" for "SYSTEM" user and return a minimalistic result as custom object `$data`: + ```powershell PS> $data = Find-TaskServiceUser -Task -Service -Server "WSRV04" -User "SYSTEM" -Minimal PS> $data ``` -5. Find tasks and services on server "WSRV04" for "JohnK" user. Display results and save it as object in XML file. Import object data from XML and display tasks and services separately: + +* Find tasks and services on server "WSRV04" for "JohnK" user. Display results and save it as object in XML file. Import object data from XML and display tasks and services separately: + ```powershell PS> Find-TaskServiceUser -Task -Service -Server "WSRV04" -User "JohnK" -Export PS> $object = Import-Clixml "D:\dane\voytas\Dokumenty\Find-TaskServiceUser.XML" @@ -59,7 +68,7 @@ Module icon made by [Freepik](https://www.freepik.com/) from [Flaticon](https:// ## Authors -* **Wojciech Napierała** - *Initial work* - [Voytas75](https://github.com/voytas75) +* **Wojciech Napierała** - *Initial work* - [Voytas75](https://github.com/voytas75) See also the list of [contributors](https://github.com/voytas75/Find-TaskServiceUser/graphs/contributors) who participated in this project. diff --git a/Write-Log.ps1 b/Write-Log.ps1 index 9c88daf..7a78ee7 100644 --- a/Write-Log.ps1 +++ b/Write-Log.ps1 @@ -1,5 +1,5 @@ function Write-Log { - param([string]$logstring) - Write-Debug -Message "Append ""$logstring"" to log file: ""$logfile""" - Add-Content $logfile -Value $logstring + param([string]$logstring) + Write-Debug -Message "Append ""$logstring"" to log file: ""$logfile""" + Add-Content $logfile -Value $logstring }