functions/Services.ps1

Function Get-Service()
{
    
}

Function Edit-Service()
{
    [CmdletBinding(SupportsShouldProcess=$True,DefaultParameterSetName='Default')]
    param
    (
        [string[]] $ComputerName,

        [string] $ComputerList,

        [ValidateSet("WMI", "External")]
        [string] $Method = "WMI",

        [string] $BinPath = $(Join-Path -Path $ModuleRoot -ChildPath "\bin"),

        [System.Management.Automation.Runspaces.PSSession[]] $Session=$Null,

        [System.Management.Automation.PSCredential] $Credential=$Null,

        [boolean] $OnlineCheck = $true,

        [string] $Name,

        [ValidateSet("start", "stop")]
        [string] $ServiceState
    )

    $returnobject = @()

    $Function = $MyInvocation.MyCommand
    Write-Verbose "Entering $Function"

    $Arguments = "Name: $Name, ServiceState $ServiceState"
    Write-Verbose $Arguments

    if (!$Name)
    {
         $Reason = 'You have to provide a service name'
        $Status = "fail"
         $returnobject += New-PowerSponseObject -Function $Function -Status $Status -Reason $Reason -Arguments $Arguments
    }
    elseif (!$ServiceState)
    {
         $Reason = 'You have to provide an ServiceState'
        $Status = "fail"
         $returnobject += New-PowerSponseObject -Function $Function -Status $Status -Reason $Reason -Arguments $Arguments
    }
    else
    {
        $targets = Get-Target -ComputerList:$(if ($ComputerList){$ComputerList}) -ComputerName:$(if ($ComputerName){$ComputerName})

        foreach ($target in $targets)
        {
            Write-Progress -Activity "Running $Function" -Status "Processing $target..."

            if ($pscmdlet.ShouldProcess($target, "$ServiceState service $($Name)"))
            {

                if ($OnlineCheck -and !(Test-Connection $target -Quiet -Count 1))
                {
                    Write-Verbose "$target is offline"
                    $Status = "fail"
                    $Reason = "offline"
                }
                else
                {
                    if ($Method -match "wmi")
                    {
                        if (($target -eq "localhost") -and $Credential)
                        {
                            $Status = "fail"
                            $Reason = "localhost and WMI and credential not working"
                            $returnobject += New-PowerSponseObject -Function $Function -Status $Status -Reason $Reason -Arguments $Arguments -ComputerName $target
                            Continue
                        }

                        $res = Get-WmiObject Win32_service -Filter "name='$($Name)'" -Credential $Credential -ComputerName $target

                        if (!$res)
                        {
                            $Status = "fail"
                            $Reason = "no service (empty result)"
                        }
                        else
                        {
                            $State = $res.State
                            write-verbose $State
                            if (($ServiceState -match "stop") -and ($State -match "stopped"))
                            {
                                $Status = "pass"
                                $Reason = "service already stopped"
                            }
                            elseif (($ServiceState -match "start") -and ($State -match "running"))
                            {
                                $Status = "pass"
                                $Reason = "service already started"
                            }
                            else
                            {
                                $rval = $res.$("$($ServiceState)Service")().returnvalue

                                write-verbose "Return value: $rval"

                                if ($rval -eq 0)
                                {
                                        $Status = "pass"
                                        $Reason = "service set to $ServiceState"
                                }
                                elseif ($rval -eq 2)
                                {
                                    $Status = "fail"
                                    $Reason = "access denied"
                                }
                                else
                                {
                                    $Status = "fail"
                                    $Reason = "Returnvalue is $rval"
                                }
                            }
                        }
                    }
                    elseif ($Method -match "winrm")
                    {
                    }
                    elseif ($Method -match "external")
                    {
                        Write-Verbose "Using external tools"
                        Write-Verbose "BinPath: $BinPath"

                        if (!(Test-Path -Path "$BinPath\psservice.exe"))
                        {
                            $Status = "fail"
                            $Reason = "Binary $BinPath\psservice.exe not found."
                        }
                        else
                        {
                            $proc = Start-Process psservice.exe -commandline "\\$target -accepteula -nobanner $ServiceState $Name"

                            if ($proc.stderr -match "verweigert" -or $proc.stderr -match "denied")
                            {
                                $Reason = "Access denied while set service to $ServiceState"
                                $Status = "fail"
                            }
                            elseif ($proc.stderr -match "bereits" -or $proc.stderr -match "already")
                            {
                                $Reason = "Service already set to $ServiceState."
                                $Status = "pass"
                            }
                            elseif ($proc.stdout -match "Error")
                            {
                                    $Reason = "Error while using psservice. Use -Verbose when running the command for more information. Is service already activated? If not, use Enable-Service or Enable-RemoteRegistry."
                                    $Status = "fail"
                                    Write-Verbose $proc.stdout
                                    Write-Verbose $proc.stderr
                            }
                            elseif ($proc.stdout -match "unable to access")
                            {
                                $Reason = "Unable to access SCM"
                                $Status = "fail"
                            }
                            elseif (!$proc.stderr -and !($proc.stdout -match "error"))
                            {
                                $Reason = "Service set to $ServiceState."
                                $Status = "pass"
                            }
                            else
                            {
                                $Status = "fail"
                                $Reason = "Tell the developer to better code. Something went wrong..."
                                Write-Verbose $proc.stdout
                                Write-Verbose $proc.stderr
                            }

                            if ($proc.ExitCode -eq 0)
                            {
                                Write-Verbose "Successfully executed psservice on $target"
                            }
                            else
                            {
                                Write-Verbose "Error while running psservice on $target"
                            }

                        } #binaries found

                    } #External

                } #online

                $returnobject += New-PowerSponseObject -Function $Function -Status $Status -Reason $Reason -Arguments $Arguments -ComputerName $target

            } #whatif

        } #each target

    } # parameters ok

    $returnobject
    Write-Verbose "Leaving $($MyInvocation.MyCommand)"

} # Edit-Service

Function Start-Service()
{
    [CmdletBinding(SupportsShouldProcess=$True,DefaultParameterSetName='ExternComputerName')]
    param
    (
        [string[]] $ComputerName,

        [string] $ComputerList,

        [ValidateSet("WMI", "WinRM", "External")]
        [string] $Method = "WMI",

        [string] $BinPath = $(Join-Path -Path $ModuleRoot -ChildPath "\bin"),

        [System.Management.Automation.Runspaces.PSSession[]] $Session=$Null,

        [System.Management.Automation.PSCredential] $Credential=$Null,

        [boolean] $OnlineCheck = $true,

        [string] $Name
    )

    $returnobject = @()

    $Function = $MyInvocation.MyCommand
    Write-Verbose "Entering $Function"

    $Arguments = "Name: $Name"
    Write-Verbose "Arguments: $Arguments"

    if (!$Name)
    {
         $Reason = 'You have to provide a service name'
        $Status = "fail"
         $returnobject += New-PowerSponseObject -Function $Function -Status $Status -Reason $Reason -Arguments $Arguments
    }
    else
    {
        $targets = Get-Target -ComputerList:$(if ($ComputerList){$ComputerList}) -ComputerName:$(if ($ComputerName){$ComputerName})

        foreach ($target in $targets)
        {
            Write-Progress -Activity "Running $Function" -Status "Processing $target..."
            if ($pscmdlet.ShouldProcess($target, "start $($Name)"))
            {
                if ($OnlineCheck -and !(Test-Connection $target -Quiet -Count 1))
                {
                    $Status = "fail"
                    $Reason = "offline"
                    $returnobject += New-PowerSponseObject -Function $Function -Status $Status -Reason $Reason -Arguments $Arguments -ComputerName $target
                }
                else
                {
                    if ($Method -match "wmi")
                    {
                        $ret = Edit-Service -Method wmi -ComputerName $target -Credential $Credential -Name $Name -servicestate "start" -OnlineCheck:$false
                    }
                    elseif ($Method -match "winrm")
                    {
                            $ret = Edit-Service -Method winrm -ComputerName $target -Name $Name -servicestate "start" -OnlineCheck:$false
                    }
                    elseif ($Method -match "external")
                    {
                            $ret = Edit-Service -Method external -ComputerName $target -Name $Name -servicestate "start" -OnlineCheck:$false
                    }

                    $ret | ? { $_.Function -match "Edit-Service" } | % { $_.Function = $Function }
                    $ret | ? { $_.Arguments -match "Edit-Service" } | % { $_.Arguments = $Arguments }
                    $returnobject += $ret
                } #online

            } #whatif

        } #each target

    } #parameters ok

    $returnobject
    Write-Verbose "Leaving $Function"

} #Start-Service

Function Stop-Service()
{
    [CmdletBinding(SupportsShouldProcess=$True,DefaultParameterSetName='Default')]
    param
    (
        [string[]] $ComputerName,

        [string] $ComputerList,

        [ValidateSet("WMI", "WinRM", "External")]
        [string] $Method = "WMI",

        [string] $BinPath = $(Join-Path -Path $ModuleRoot -ChildPath "\bin"),

        [System.Management.Automation.Runspaces.PSSession[]] $Session=$Null,

        [System.Management.Automation.PSCredential] $Credential=$Null,

        [boolean] $OnlineCheck = $true,

        [string] $Name
    )

    $returnobject = @()

    $Function = $MyInvocation.MyCommand
    Write-Verbose "Entering $Function"

    $Arguments = "Name: $Name, OnlineCheck: $OnlineCheck"
    Write-Verbose "Arguments: $Arguments"

    if (!$Name)
    {
         $Reason = 'You have to provide a service name'
        $Status = "fail"
         $returnobject += New-PowerSponseObject -Function $Function -Status $Status -Reason $Reason -Arguments $Arguments
    }
    else
    {
        $targets = Get-Target -ComputerList:$(if ($ComputerList){$ComputerList}) -ComputerName:$(if ($ComputerName){$ComputerName})

        Write-Verbose $targets

        foreach ($target in $targets)
        {
            Write-Progress -Activity "Running $Function" -Status "Processing $target..."
            if ($pscmdlet.ShouldProcess($target, "Stop $($Name)"))
            {
                if ($OnlineCheck -and !(Test-Connection $target -Quiet -Count 1))
                {
                    $Status = "fail"
                    $Reason = "offline"
                    $returnobject += New-PowerSponseObject -Function $Function -Status $Status -Reason $Reason -Arguments $Arguments -ComputerName $target
                }
                else
                {
                    if ($Method -match "wmi")
                    {
                        $ret = Edit-Service -Method wmi -ComputerName $target -Credential $Credential -Name $Name -servicestate "stop" -OnlineCheck:$false
                    }
                    elseif ($Method -match "winrm")
                    {
                            $ret = Edit-Service -Method WinRM -ComputerName $target -Name $Name -servicestate "stop" -OnlineCheck:$false
                    }
                    elseif ($Method -match "external")
                    {
                            $ret = Edit-Service -Method external -ComputerName $target -Name $Name -servicestate "stop" -OnlineCheck:$false
                    }

                    $ret | ? { $_.Function -match "Edit-Service" } | % { $_.Function = $Function }
                    $ret | ? { $_.Arguments -match "Edit-Service" } | % { $_.Arguments = $Arguments }

                    $returnobject += $ret

                } #online

            } #whatif

        } #each target

    } #parameters ok

    $returnobject
    Write-Verbose "Leaving $($MyInvocation.MyCommand)"

} #Stop-Service

Function Enable-Service()
{
    [CmdletBinding(SupportsShouldProcess=$True,DefaultParameterSetName='ExternComputerName')]
    param
    (
        [string[]] $ComputerName,

        [string] $ComputerList,

        [ValidateSet("WMI", "External")]
        [string] $Method = "WMI",

        [string] $BinPath = $(Join-Path -Path $ModuleRoot -ChildPath "\bin"),

        [System.Management.Automation.Runspaces.PSSession[]] $Session=$Null,

        [System.Management.Automation.PSCredential] $Credential=$Null,

        [boolean] $OnlineCheck = $true,

        [string] $Name,

        [ValidateSet("Manual", "Automatic")]
        [string] $StartupType
    )

    $returnobject = @()

    $Function = $MyInvocation.MyCommand
    Write-Verbose "Entering $Function"

    $Arguments = "Name: $Name, StartupType: $StartupType, Method: $Method"
    Write-Verbose "Arguments: $Arguments"

    if ($Method -match "external")
    {
        if ($StartupType -eq "Manual")
        {
            $StartupTypeService = "demand"
        }
        else
        {
            $StartupTypeService = "auto"
        }
    }
    else
    {
        $StartupTypeService = $StartupType
    }

    if (!$Name)
    {
         $Reason = 'You have to provide a service name'
        $Status = "fail"
         $returnobject += New-PowerSponseObject -Function $Function -Status $Status -Reason $Reason -Arguments $Arguments
    }
    elseif (!$StartupType)
    {
         $Reason = 'You have to specifiy the startuptype. Manual or Automatic.'
        $Status = "fail"
         $returnobject += New-PowerSponseObject -Function $Function -Status $Status -Reason $Reason -Arguments $Arguments
    }
    else
    {
        $targets = Get-Target -ComputerList:$(if ($ComputerList){$ComputerList}) -ComputerName:$(if ($ComputerName){$ComputerName})

        foreach ($target in $targets)
        {
            Write-Progress -Activity "Running $Function" -Status "Processing $target..."
            if ($pscmdlet.ShouldProcess($target, "Enable $($Name) with StartupType $($StartupTypeService)"))
            {
                if ($OnlineCheck -and !(Test-Connection $target -Quiet -Count 1))
                {
                    Write-Verbose "$target is offline"
                    $Status = "fail"
                    $Reason = "offline"
                }
                else
                {
                    if ($Method -match "wmi")
                    {
                        if (($target -eq "localhost") -and $Credential)
                        {
                            $Status = "fail"
                            $Reason = "localhost and WMI and credential not working"
                            $returnobject += New-PowerSponseObject -Function $Function -Status $Status -Reason $Reason -Arguments $Arguments -ComputerName $target
                            Continue
                        }

                        $res = Get-WmiObject Win32_service -Filter "name='$($Name)'" -Credential $Credential -ComputerName $target

                        if (!$res)
                        {
                            $Status = "fail"
                            $Reason = "no service"
                        }
                        else
                        {
                            $rval = $res.ChangeStartMode($StartupTypeService).returnvalue
                            write-verbose "Return value: $rval"

                            if ($rval -eq 0)
                            {
                                $Status = "pass"
                                $Reason = "service enabled"
                            }
                            elseif ($rval -eq 2)
                            {
                                $Status = "fail"
                                $Reason = "access denied"
                            }
                            else
                            {
                                $Status = "fail"
                                $Reason = "Returnvalue is $rval"
                            }
                        }
                    }
                    elseif ($Method -match "winrm")
                    {
                    }
                    elseif ($Method -match "external")
                    {
                        Write-Verbose "Using external tools"
                        Write-Verbose "BinPath: $BinPath"

                        if (!(Test-Path -Path "$BinPath\psservice.exe"))
                        {
                            $Status = "fail"
                            $Reason = "Binary $BinPath\psservice.exe not found."
                        }
                        else
                        {

                            $proc = Start-Process psservice.exe -commandline "\\$target -accepteula -nobanner setconfig $($Name) $($StartupTypeService)"

                            if ($proc.stderr -match "verweigert" -or $proc.stderr -match "denied")
                            {
                                $Reason = "Access denied while enabling $Name"
                                $Status = "fail"
                            }
                            elseif ($proc.stderr -match "kein installierter" -or $proc.stderr -match "no installed")
                            {
                                $Reason = "service not found"
                                $Status = "fail"
                            }
                            elseif ($proc.stderr -match "deaktiviert" -or $proc.stderr -match "deactivated")
                            {
                                $Reason = "service is deactivated"
                                $Status = "fail"
                            }
                            elseif ($proc.stdout -match "error" -or $proc.stdout -match "usage:")
                            {
                                $Reason = "Error while using psservice"
                                $Status = "fail"
                                Write-Verbose $proc.stdout
                                Write-Verbose $proc.stderr
                            }
                            elseif ($proc.stdout -match "unable to access")
                            {
                                $Reason = "Unable to access service control manager"
                                $Status = "fail"
                            }
                            elseif ($proc.stdout -and !($proc.stdout -match "error"))
                            {
                                $Reason = "$($Name) enabled."
                                $Status = "pass"
                            }
                            else
                            {
                                $Reason = "Unspecified error"
                                $Status = "fail"
                                Write-Verbose $proc.stdout
                                Write-Verbose $proc.stderr
                            }

                            if ($proc.ExitCode -eq 0)
                            {
                                Write-Verbose "Successfully executed psservice on $target"
                            }
                            else
                            {
                                Write-Verbose "Error while running psservice on $target"
                            }

                        } #Binary found

                    } #External

                } #online

                $returnobject += New-PowerSponseObject -Function $Function -Status $Status -Reason $Reason -Arguments $Arguments -ComputerName $target
            } #whatif

        } #each target

    } #parameters ok

    $returnobject
    Write-Verbose "Leaving $($MyInvocation.MyCommand)"
} #Enable-Service

Function Disable-Service()
{
    [CmdletBinding(SupportsShouldProcess=$True,DefaultParameterSetName='Default')]
    param
    (
        [string[]] $ComputerName,

        [string] $ComputerList,

        [ValidateSet("WMI", "External")]
        [string] $Method = "WMI",

        [string] $BinPath = $(Join-Path -Path $ModuleRoot -ChildPath "\bin"),

        [System.Management.Automation.Runspaces.PSSession[]] $Session=$Null,

        [System.Management.Automation.PSCredential] $Credential=$Null,

        [boolean] $OnlineCheck = $true,

        [switch] $NoRemoteRegistry,

        [string] $Name
    )

    $returnobject = @()

    $Function = $MyInvocation.MyCommand
    Write-Verbose "Entering $Function"

    $Arguments = "Method: $Method, Name: $Name, Onlinecheck: $OnlineCheck"
    Write-Verbose "Arguments: $Arguments"

    if (!$Name)
    {
         $Reason = 'You have to provide a service name'
        $Status = "fail"
        $returnobject += New-PowerSponseObject -Function $Function -Status $Status -Reason $Reason -Arguments $Arguments
    }
    else
    {
        $targets = Get-Target -ComputerList:$(if ($ComputerList){$ComputerList}) -ComputerName:$(if ($ComputerName){$ComputerName})

        foreach ($target in $targets)
        {
            Write-Progress -Activity "Running $Function" -Status "Processing $target..."
            if ($pscmdlet.ShouldProcess($target, "Disable Service $($Name)"))
            {
                if ($OnlineCheck -and !(Test-Connection $target -Quiet -Count 2))
                {
                    Write-Verbose "$target is offline"
                    $Status = "fail"
                    $Reason = "offline"
                }
                else
                {

                    if ($Method -match "wmi")
                    {

                        if (($target -eq "localhost") -and $Credential)
                        {
                            $Status = "fail"
                            $Reason = "localhost and WMI and credential not working"
                            $returnobject += New-PowerSponseObject -Function $Function -Status $Status -Reason $Reason -Arguments $Arguments -ComputerName $target
                            Continue
                        }

                        if ($Credential)
                        {
                            Write-Verbose "Using wmi with credentials"
                            # todo fixme add regex capability with wmi filter or with list all and -match with PS
                            $res = Get-WmiObject Win32_service -Filter "name='$($Name)'" -Credential $Credential -ComputerName $target
                        }
                        else
                        {
                            # todo fixme add regex capability with wmi filter or with list all and -match with PS
                            Write-Verbose "Using wmi without credentials"
                            $res = Get-WmiObject Win32_service -Filter "name='$($Name)'" -ComputerName $target
                        }

                        if (!$res)
                        {
                            $Status = "fail"
                            $Reason = "no service"
                        }
                        else
                        {
                            $rval = $res.ChangeStartMode('disabled').returnvalue
                            write-verbose "Return value: $rval"

                            if ($rval -eq 0)
                            {
                                $Status = "pass"
                                $Reason = "service disabled"
                            }
                            elseif ($rval -eq 2)
                            {
                                $Status = "fail"
                                $Reason = "Access denied to disable service"
                            }
                            else
                            {
                                $Status = "fail"
                                $Reason = "Returnvalue is $rval"
                            }
                        }
                    }
                    elseif ($Method -match "winrm")
                    {
                        # noooot
                    }
                    elseif ($Method -match "external")
                    {

                        Write-Verbose "Using external tools"
                        Write-Verbose "BinPath: $BinPath"

                        if (!(Test-Path -Path "$BinPath\psservice.exe"))
                        {
                            $Status = "fail"
                            $Reason = "Binary $BinPath\psservice.exe not found."
                        }
                        else
                        {
                            $proc = Start-Process psservice.exe -commandline "\\$target -accepteula -nobanner setconfig $Name disabled"

                            if ($proc.stderr -match "verweigert" -or $proc.stderr -match "denied")
                            {
                                $Reason = "Access denied while disabling service"
                                $Status = "fail"
                            }
                            elseif ($proc.stdout -match "Unable")
                            {
                                $Reason = "Error accessing remote host"
                                $Status = "fail"
                            }
                            elseif ($proc.stdout -and !($proc.stdout -match "Error"))
                            {
                                $Reason = "Service disabled"
                                $Status = "pass"
                            }
                            else
                            {
                                $Reason = "Tell the developer to better code. Something went wrong..."
                                $Status = "fail"
                                Write-verbose $proc.stdout
                                Write-verbose $proc.stderr
                            }

                            if ($proc.ExitCode -eq 0)
                            {
                                Write-verbose "Successfully executed psservice on $target"
                            }
                            else
                            {
                                Write-Verbose "Error while running psservice on $target"
                            }

                        } # binaries found

                    } # UseExternal

                } # host online

                $returnobject += New-PowerSponseObject -Function $Function -Status $Status -Reason $Reason -Arguments $Arguments -ComputerName $target

            } # whatif

        } # each target

    } # parameters ok

    $returnobject
    Write-Verbose "Leaving $($MyInvocation.MyCommand)"

} # Disable-Service

Function Remove-Service()
{
    
}