RobamaTools.psm1

function Add-ScheduledReboot
{
<#
.Synopsis
   Schedule a reboot for one or more computers.
.DESCRIPTION
   This function will schedule a reboot for one or more computers using psremoting. You will be able to
   specify the exakt time of the reboot, name for the job and wether the reboot will be forced or not, meaning
   logging of any existing user sessions. This will eliminate the need for you to remote to every server and
   schedule a reboot.
.EXAMPLE
   Add-ScheduledReboot -Computername Server1, Server2 -DateTime (Get-Date).Addhours(10)
 
   This will schedule a reboot on server1 and server 2 10 hours from now using psremoting.
 
.EXAMPLE
   $Computers = Get-adcomputer -filter 'name -like "*server*"'
   $Computers | Select-Object -Property @{n="Computername";E={$_.name}} |
        Add-ScheduledReboot -DateTime (Get-date -Hour 23 -minute 15)
 
   The first line will find computers named something like *server* from your domain.
   The second line recalculates the property name from adcomputer to Computername so it can be passed into the function
   Add-Scheduledreboot and then schedule a reboot to this day 23:15
 
.EXAMPLE
   Add-ScheduledReboot -DateTime (Get-date -Hour 23 -minute 15)
 
   This will schedule a reboot at 23:15. The reboot will not be forced meaning that no one can be logged in to the machine once the job runs.
 
.EXAMPLE
   Add-ScheduledReboot -DateTime (Get-date -Hour 23 -minute 15) -Force
 
   This will schedule a reboot at 23:15. The reboot will be forced so any users logged in will be kicked out once the job runs.
 
.EXAMPLE
   Add-ScheduledReboot -DateTime (get-date).addminutes(10)
 
   This will schedule a reboot 10 minutes from now.
 
.EXAMPLE
    $Date = (Get-date).adddays(1)
    
    Add-ScheduledReboot -DateTime $Date -Force
 
    This will schedule a reboot 1 day from now. The datetime object is stored in the $Date variable.
.NOTES
     
    Created by:
    Robert Amartinesei
    robertamartinesei@gmail.com
 
#>



#Requires -Version 3

    [CmdletBinding()]

    Param
    (
        #One or more computernames
        [Parameter(ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [String[]]$Computername = 'Localhost',

        #DateTime object. Use Get-Date to generate one.
        [Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName,
                    Helpmessage="A datetime object. Use Get-Date to generate one")]
        [DateTime]$DateTime,

        #Force the computer restart to occur even if users are logged in.
        [Switch]$Force,

        #Define the name of the scheduled job
        [String]$Jobname = "ScheduledReboot"
    )

    
    #Start Begin Block
    Begin
    {

        #Initiate session against $computername.
        Write-Verbose -Message "Initiating session against computers"
        $Session = New-PSSession -ComputerName $Computername

        #Set the ForceReboot variable to boolean value so it can be passed into invoke-command.
        if ($PSBoundParameters.ContainsKey("Force")){
            Write-Verbose -Message "Create the reboot job with the force parameter"
            $ForceReboot = $True
        }else {
            Write-Verbose -Message "Create the reboot job without the force parameter"
            $ForceReboot = $false
        }


    }

    #Start process block
    Process
    {

        foreach ($Computer in $Computername) {
            Write-Verbose -Message "Contacting $Computer"
            #Send command to schedule a reboot
            Write-Verbose -Message "Creating job on $Computer"
            Invoke-Command -ComputerName $Computer -ArgumentList $DateTime,$ForceReboot,$Jobname -ScriptBlock {
             
            
                #Send parameter into session against $computer
                Param (
                    $DateTime,
                    $ForceReboot,
                    $Jobname
                )
                
                #Specify options for the scheduled job.
                $JobTrigger = New-JobTrigger -Once -At $DateTime
                $JobOption = New-ScheduledJobOption -RunElevated -MultipleInstancePolicy IgnoreNew -WakeToRun -ContinueIfGoingOnBattery -StartIfOnBattery -StartIfIdle

                #Set a force parameter based on the bool value of force reboot.
                if ($ForceReboot) {
                
                    #Forces users to log off
                    $Sblock = {Restart-Computer -Force}

                }else {
                    
                    #Restarts computer if no one is logged on.
                    $Sblock = {Restart-Computer}  
                }
                

                #Register scheduled job. Return a scheduledjob object.
                Register-ScheduledJob -ScriptBlock $Sblock -ScheduledJobOption $JobOption -Trigger $JobTrigger -Name "$JobName"
                
            }

        }

    }

    #Start end block
    End
    {

        #Close the sessions
        Write-Verbose -Message "Close the sessions"
        $Session | Remove-PSSession

    }


}

function Set-Driveletter {
<#
.Synopsis
   Change a driveletter
.DESCRIPTION
   This will change to a new driveletter from any current one using the WMI Class win32_volume
 
.EXAMPLE
 
    Get-volume | where-object {$_.driveletter -eq 'K'} | Set-Driveletter -NewDriveletter L
 
    This will get the volume with the driveletter K and set it to L
 
.EXAMPLE
 
    Set-Driveletter -Driveletter K -NewDriveletter L -Whatif
    What if: Performing the operation "Change driveletter do "L:"" on target "K:".
 
    demonstrating the whatif support for the function
     
.NOTES
     
    Created by:
    Robert Amartinesei
    robertamartinesei@gmail.com
 
#>


    [Cmdletbinding(SupportsShouldprocess)]

    Param (
        [Parameter(Mandatory,Valuefrompipelinebypropertyname)]
        [ValidatePattern('^[a-z]$')]
        #Provide the driveletter you would like to change.
        [string]$Driveletter,

        [Parameter(Mandatory)]
        [ValidatePattern('^[a-z]$')]
        #Provide the new driveletter you would like to change to.
        [string]$NewDriveletter
    )

    
    #Change driveletters to a string format with colon (":") at the end.
    $Driveletter = "$($Driveletter):"
    $NewDriveLetter = "$($NewDriveLetter):"

    #Loads the current wmiobject containing the volume
    $CurrentVolume = Get-WmiObject -Query "Select * from win32_volume where driveletter='$Driveletter'"
    
    #Support whatif and verbose
    if ($pscmdlet.shouldprocess("$Driveletter","Change driveletter do `"$NewDriveLetter`"")){
        
        #Changing and setting the value
        $CurrentVolume.Driveletter = "$NewDriveLetter"
        $CurrentVolume.put()
    }
}

function Get-ItemSize {
<#
.Synopsis
   Gets some sizes based on the path
.DESCRIPTION
   Will get you some sizes in readble format for the path parameter. If the path supplied is a directory then the function will measure recurseively otherwise
   it will look at just that item
.EXAMPLE
   Get-ItemSize -path C:\Folder
.EXAMPLE
   Get-ItemSize -path C:\File.txt
.INPUTS
   Inputs to this cmdlet (if any)
.OUTPUTS
   Output from this cmdlet (if any)
.NOTES
   Robert Amartinesei
#>

    param (
        [string]$Path
    )
    Begin {
        $PathObj = get-item $Path
        if (($PathObj -is [System.IO.DirectoryInfo])) { 
            $recurse = $true
        }else {
            $recurse = $false
        }

    }

    Process {
        $Content = Get-ChildItem -Path $Path -Recurse:$recurse
        $Size = $Content | Measure-Object -Property length -Sum -Average -Maximum -Minimum -ErrorAction Stop      

        $CustomObject = [ordered]@{
            'Path' = $PathObj.FullName
            'SizeMB' = $size.Sum / 1mb -as [float]
            'SizeGB' = $size.sum / 1gb -as [float]
            'MaximumFileSizeMB' = $size.Maximum / 1mb -as [float]
            'MinimumFileSizeMB' = $size.Minimum / 1mb -as [float]
            'AverageFileSizeMB' = $size.Average / 1mb -as [float]
        }

        New-Object -TypeName psobject -Property $CustomObject
    }

    End {
    
    }


}

Function Convert-SDDLToACL {
<#
.Synopsis
   Convert SDDL String to ACL Object
.DESCRIPTION
   Converts one or more SDDL Strings to a human readable format.
.EXAMPLE
   Convert-SDDLToACL -SDDLString (get-acl .\path).sddl
.EXAMPLE
   Convert-SDDLToACL -SDDLString "O:S-1-5-21-1559460989-2589464504-629046386-3966G:DUD:(A;OICIID;FA;;;SY)(A;OICIID;FA;;;BA)(A;OICIID;FA;;;S-1-5-21-1559460989-2589464504-629046386-3966)"
.NOTES
   Robert Amartinesei
#>

    [Cmdletbinding()]

    param (
        #One or more strings of SDDL syntax.
        [string[]]$SDDLString
    )

    
    foreach ($SDDL in $SDDLString) {
        
        $ACLObject = New-Object -TypeName System.Security.AccessControl.DirectorySecurity
        $ACLObject.SetSecurityDescriptorSddlForm($SDDL)

        $ACLObject.Access

        
    
    }
}