Usefull powershell scripts
function to sum durations found in text and report total minutes
function sum_durations_from_text($text) {
<#
read multiline text containing time durations like 01:37:54 or 37:54
from each line keep only the LAST such duration
return the sum of all durations in minutes
EXAMPLE
-------
sum_durations_from_text """
Fixed Calls
5:20:23 PM dpapa (211) ndemou (220) 220 211 06:08
Teams Calls
Dimitris Papageorgiou 03-May-22 14:06 00:41 Outgoing
Dimitris Papageorgiou 03-May-22 11:35 03:41 Tuesday Incoming
Mobile calls
see 2 screenshots 1:24:00
"""
...
94
#>
$mins = (
$text -split "`n" | %{
$_ = $_.TrimEnd()
write-host -NoNewline -foregroundcolor white "$_"
$_
} | %{
# split line on spaces and keep only "words" that match digit:digit
# and from these "words" keep only the last one
$fields = ($_ -split ' ' | ?{ $_ -match '[0-9]:[0-9]' })
$time = $null
if ($fields -is [array]) {$time = $fields[-1]}
if ($fields -is [string]) {$time = $fields}
if ($time) {
write-host -NoNewline -foregroundcolor yellow " --> "
write-host -foregroundcolor cyan "$time"
} else {
write-host ""
}
$time
} | %{
$time = ($_ -split ":")
if ($time.Length -eq 3) { # hh:mm:ss
$mins = ($time[0] -as [int])*60
$mins += ($time[1] -as [int])
$mins += ($time[2] -as [int])/60
} else { # mm:ss
$mins = ($time[0] -as [int])
$mins += ($time[1] -as [int])/60
}
$mins
} | Measure-Object -sum
).sum
$mins -as [int]
}
Change fields in active directory
If you need to change for example the job title of the users
Import-Module ActiveDirectory
$data = import-csv -path C:\Users\Administrator\Desktop\scripts\vathmides.csv
foreach ($user in $data)
{
$mailonly=$user.mail
$aduser= Get-ADUser -Filter {EmailAddress -eq $mailonly}
if ($aduser.Length) {
echo "ERROR: $($aduser.length) results for $mailonly"
} else {
if (-not $aduser.Name) {
echo "ERROR: no user with email $mailonly"
} else {
echo "$($aduser.Name) $mailonly new title will be $($user.title)"
Get-ADUser -Filter {EmailAddress -eq $mailonly} | Set-ADUser -Replace @{title = $user.title
}}}}
how the csv should look"mail","title"
"thanos.aggeloudis@mazars.gr","Assistant"
"vasilis.agortsas@mazars.gr","Senior 3"
"ioannis.alexandridis@mazars.gr","Manager "
Recursively take ownership of a directory safely
To recursively take ownership of a directory most sites sugest to run
takeown
with options
/r /D y
. But if the administrator that runs this command does not have list/read access in any subfolder this command will DELETE EXISTING PERMISSIONS! (see this
serverfault answer).
The solution is this:
https://serverfault.com/a/1123477/67528
Listen to TCP port to test firewall
function Listen-Port ($port=80){
<#
.DESCRIPTION
Temporarily listen on a given port for connections dumps connections to the screen - useful for troubleshooting
firewall rules.
.PARAMETER Port
The TCP port that the listener should attach to
.EXAMPLE
PS C:\> listen-port 443
Listening on port 443, press CTRL+C to cancel
DateTime AddressFamily Address Port
-------- ------------- ------- ----
3/1/2016 4:36:43 AM InterNetwork 192.168.20.179 62286
Listener Closed Safely
.INFO
Created by Shane Wright. Neossian@gmail.com
#>
$endpoint = new-object System.Net.IPEndPoint ([system.net.ipaddress]::any, $port)
$listener = new-object System.Net.Sockets.TcpListener $endpoint
$listener.server.ReceiveTimeout = 3000
$listener.start()
try {
Write-Host "Listening on port $port, press CTRL+C to cancel"
While ($true){
if (!$listener.Pending())
{
Start-Sleep -Seconds 1;
continue;
}
$client = $listener.AcceptTcpClient()
$client.client.RemoteEndPoint | Add-Member -NotePropertyName DateTime -NotePropertyValue (get-date) -PassThru
$client.close()
}
}
catch {
Write-Error $_
}
finally{
$listener.stop()
Write-host "Listener Closed Safely"
}
}
List of latest logins/logouts
function get-logonhistory{
Param (
[string]$Computer = (Read-Host Remote computer name),
[int]$Days = 10
)
cls
$Result = @()
Write-Host "Gathering Event Logs, this can take awhile..."
$ELogs = Get-EventLog System -Source Microsoft-Windows-WinLogon -After (Get-Date).AddDays(-$Days) -ComputerName $Computer
If ($ELogs)
{ Write-Host "Processing..."
ForEach ($Log in $ELogs)
{ If ($Log.InstanceId -eq 7001)
{ $ET = "Logon"
}
ElseIf ($Log.InstanceId -eq 7002)
{ $ET = "Logoff"
}
Else
{ Continue
}
$Result += New-Object PSObject -Property @{
Time = $Log.TimeWritten
'Event Type' = $ET
User = (New-Object System.Security.Principal.SecurityIdentifier $Log.ReplacementStrings[1]).Translate([System.Security.Principal.NTAccount])
}
}
$Result | Select Time,"Event Type",User | Sort Time -Descending | Out-GridView
Write-Host "Done."
}
Else
{ Write-Host "Problem with $Computer."
Write-Host "If you see a 'Network Path not found' error, try starting the Remote Registry service on that computer."
Write-Host "Or there are no logon/logoff events (XP requires auditing be turned on)"
}
}
# USAGE:
get-logonhistory -Computer ComputerName -Days 30
List all processes and their users
$ProcessList = Get-CimInstance -Query "SELECT * from Win32_Process"
foreach ($proc in ($ProcessList)) {
$ProcessInfo=Invoke-CimMethod -InputObject $proc -MethodName GetOwner
$proc_id = $proc.processid
$proc_name = $proc.Name
$proc_user = $ProcessInfo.User
if ($proc_user -eq "dhcpdns") {echo "$proc_id, $proc_name, $proc_user"} else {echo "."}
#echo "$proc_id, $proc_name, $proc_user"
}
Check the disk usage of a directory
Example usage:
Get-DirSize -path "c:\Users" | Sort-Object -Property size
function Get-DirSize {
<#
.Synopsis
Gets a list of directories and sizes.
.Description
This function recursively walks the directory tree and returns the size of
each directory found.
.Parameter path
The path of the root folder to start scanning.
.Example
(Get-DirSize $env:userprofile | sort Size)[-2]
Get the largest folder under the user profile.
.Example
Get-DirSize -path "c:data" | Sort-Object -Property size
Displays folders and sub folders from c:data in descending size order
.Outputs
[PSObject]
.Notes
NAME: Get-DirSize
AUTHOR: ToJo2000
LASTEDIT: 8/12/2009
KEYWORDS: 2009 Summer Scripting Games, Beginner Event 8, Get-ChildItem, Files and Folders
.Link
Http://www.ScriptingGuys.com
#Requires -Version 2.0
#>
param([Parameter(Mandatory = $true, ValueFromPipeline = $true)][string]$path)
BEGIN {}
PROCESS{
$size = 0
$folders = @()
foreach ($file in (Get-ChildItem $path -Force -ea SilentlyContinue)) {
if ($file.PSIsContainer) {
$subfolders = @(Get-DirSize $file.FullName)
$size += $subfolders[-1].Size
$folders += $subfolders
} else {
$size += $file.Length
}
}
$object = New-Object -TypeName PSObject
$object | Add-Member -MemberType NoteProperty -Name Folder `
-Value (Get-Item $path).FullName
$object | Add-Member -MemberType NoteProperty -Name Size -Value $size
$folders += $object
Write-Output $folders
}
END {}
} # end function Get-DirSize
Regarding open files on a server
Get a list of files open on the server
From
https://gallery.technet.microsoft.com/scriptcenter/ef8de213-45b6-4751-8c77-01d1b6623e16 (A collection of functions that are helpful with managing local computers. These functions perform at their best when they are used in conjunction with my
ActiveDirectory library. For example you could add a local account to all the computers in a particular OU, or get a list of running services on your Domain Controllers.)
Also read this thread
https://social.technet.microsoft.com/Forums/windowsserver/en-US/67e94a6a-47e8-420a-b28a-759d876fb15e/how-to-list-open-files-using-powershell?forum=winserverpowershell
And there is the DOS command:
openfiles /query /v | findstr /i /c:"some part of a folder name"
Function Get-OpenFiles
{
<#
.SYNOPSIS
Get a list of files open on the server
.DESCRIPTION
This function returns a list of files open on a given server. The output is
similar to that of the Manage Open Files from the Share and Storage Management
console.
.PARAMETER ComputerName
The NetBIOS or FQDN of the computer
.EXAMPLE
Get-OpenFiles -ComputerName fs
User Path LockCount
---- ---- ---------
User1 F:\Users\User1\Documents\Data\... 0
User2 P:\Public 0
Description
-----------
This example shows the basic usage of this command.
.NOTES
FunctionName : Get-OpenFiles
Created by : Jeff Patton
Date Coded : 09/26/2011 13:01:38
.LINK
https://code.google.com/p/mod-posh/wiki/ComputerManagement#Get-OpenFiles
#>
[CmdletBinding()]
Param
(
$ComputerName = (hostname)
)
Begin
{
$OpenFiles = @()
$Server = [adsi]"WinNT://$($ComputerName)/LanmanServer"
$Resources = $Server.PSBase.Invoke("Resources")
}
Process
{
foreach ($Resource in $Resources)
{
Try
{
$UserResource = New-Object -TypeName PSobject -Property @{
User = $Resource.GetType().InvokeMember("User","GetProperty",$null,$Resource,$null)
Path = $Resource.GetType().InvokeMember("Path","GetProperty",$null,$Resource,$null)
LockCount = $Resource.GetType().InvokeMember("LockCount","GetProperty",$null,$Resource,$null)
}
}
Catch
{
}
$OpenFiles += $UserResource
}
}
End
{
Return $OpenFiles
}
}
Create a list of which users open what files
You can schedule this to run daily on a file server in order to collect to c:\openfiles.csv a list of which user opens what files ( username ; c:\path\to\file)
# run a few times every several seconds and collect a list
# of who user has what file open in a csv file
# only unique entries are found in the final csv file
# Nick Demou, 2019
function afewtimes {
Write-Host "Capturing open files..."
For ($i=1; $i -le 20; $i++) { # 20 times * ~3mins each => ~1hour
$cnt = 0
$last = ""
net files |select-string "[:]" | %{ $_ -replace ' .*', '' } | select-string "[0-9]" | ForEach-Object {
$out = (net files "$_" 2> $null | select-string "^User name|^Path|^$")
$out = %{ $out -replace '^User name *', '' }
$out = %{ $out -replace '^Path *', ' ; ' }
$cnt += 1
if ($out -ne "") {
$last=$out
write-output "$out"
}
}
Write-Host "$cnt open files, last: $last"
sleep 180 # 3mins
}
}
$hours=11
For ($i=1; $i -le $hours; $i++) {
afewtimes | Select-Object -Unique > c:\openfiles.tmp
cat c:\openfiles.tmp >> c:\openfiles.txt
}