functions/Computer.ps1
Function Restart-Computer() { [CmdletBinding(SupportsShouldProcess=$True)] param( [string[]] $ComputerName, [string] $ComputerList, [ValidateSet("external", "wmi")] [string] $Method = "wmi", [string] $BinPath = $(Join-Path -Path $ModuleRoot -ChildPath "\bin"), [switch] $NoRemoteRegistry, [System.Management.Automation.Runspaces.PSSession[]] $Session=$Null, [System.Management.Automation.PSCredential] $Credential=$Null, [boolean] $OnlineCheck = $true ) # when using pssexec, a cleanup is not possible after shutdown, obviously # $Function = $MyInvocation.MyCommand Write-Verbose "Entering $Function" # when using psexec wait until client is online again and cleanup services $ret = Edit-Computer -Command "reboot" -Credential $Credential -ComputerList:$(if ($ComputerList){$ComputerList}) -ComputerName:$(if ($ComputerName){$ComputerName}) -OnlineCheck:$OnlineCheck -Method:$Method -NoRemoteRegistry:$NoRemoteRegistry -BinPath:$BinPath $ret | ? {$_.Function -match "Edit-Computer" } | % { $_.Function = "Restart-Computer" } $ret Write-Verbose "Leaving $Function" } Function Stop-Computer() { [CmdletBinding(SupportsShouldProcess=$True)] param( [string[]] $ComputerName, [string] $ComputerList, [ValidateSet("external", "wmi")] [string] $Method = "wmi", [string] $BinPath = $(Join-Path -Path $ModuleRoot -ChildPath "\bin"), [switch] $NoRemoteRegistry, [System.Management.Automation.Runspaces.PSSession[]] $Session=$Null, [System.Management.Automation.PSCredential] $Credential=$Null, [boolean] $OnlineCheck = $true ) # when using pssexec, a cleanup is not possible after shutdown, obviously # $Function = $MyInvocation.MyCommand Write-Verbose "Entering $Function" # when using psexec wait until client is online again and cleanup services $ret = Edit-Computer -Command "shutdown" -Credential $Credential -ComputerList:$(if ($ComputerList){$ComputerList}) -ComputerName:$(if ($ComputerName){$ComputerName}) -OnlineCheck:$OnlineCheck -Method:$Method -NoRemoteRegistry:$NoRemoteRegistry -BinPath:$BinPath $ret | ? {$_.Function -match "Edit-Computer" } | % { $_.Function = "Shutdown-Computer" } $ret Write-Verbose "Leaving $Function" } Function Edit-Computer() { [CmdletBinding(SupportsShouldProcess=$True,DefaultParameterSetName='Default')] param ( [string[]] $ComputerName, [string] $ComputerList, [ValidateSet("wmi")] [string] $Method = "wmi", [string] $BinPath = $(Join-Path -Path $ModuleRoot -ChildPath "\bin"), [switch] $NoRemoteRegistry, [System.Management.Automation.Runspaces.PSSession[]] $Session=$Null, [System.Management.Automation.PSCredential] $Credential=$Null, [boolean] $OnlineCheck = $true, [ValidateSet("reboot", "shutdown")] [string] $Command ) $Function = $MyInvocation.MyCommand Write-Verbose "Entering $Function" $returnobject = @() $Arguments = "Command $Command, OnlineCheck: $OnlineCheck" Write-Verbose $Arguments if ($PSBoundParameters.ContainsKey('whatif') -and $PSBoundParameters['whatif'].ispresent) { $WhatIfPassed = $true } else { $WhatIfPassed = $false } Write-Verbose "whatif: $WhatIfPassed" if ($PSBoundParameters.ContainsKey('NoRemoteRegistry') -and $PSBoundParameters['NoRemoteRegistry']) { $NoRemoteRegistry = $true } else { $NoRemoteRegistry = $false } Write-Verbose "NoRemoteRegistry $NoRemoteRegistry" if (!$Command) { $Reason = 'You have to provide an command, e.g. value reboot or shutdown for parameter -Command' $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..." $IsLocalhost = ($target -match "localhost") Write-Verbose "Localhost: $IsLocalhost" if (!$IsLocalhost -and $OnlineCheck -and !(Test-Connection $target -Quiet -Count 1)) { Write-Verbose "$target is offline" $Status = "fail" $Reason = "offline" } else { if ($Method -match "wmi") { # https://msdn.microsoft.com/en-us/library/aa394058(v=vs.85).aspx # Win32Shutdown method of the Win32_OperatingSystem class # 2 reboot # 8 shutdown <# $ret = get-wmiobject win32_operatingsystem -computername $computername | invoke-wmimethod -name Win32Shutdown -argumentlist $_action # The Reboot method can be used to restart a computer. Like the # Win32Shutdown method, the Reboot method requires the user whose # security credentials are being used by the script to possess the # Shutdown privilege. gwmi win32_operatingsystem -ComputerName xxxxxxxxxxxx | Invoke-WmiMethod -Name shutdown # This method immediately shuts the computer down, if possible. The # system stops all running processes, flushes all file buffers to the # disk, and then powers down the system. The calling process must # have the SE_SHUTDOWN_NAME privilege, as described in the following # example. # # (gwmi win32_operatingsystem).psbase.Scope.Options.EnablePrivileges = $true #> # todo test what is displayed to the user after reboot or shutdown # todo add switch to wait until reboot is finished and host wieder online if ($pscmdlet.ShouldProcess($target, "$Command")) { try { $ret = gwmi win32_operatingsystem -ComputerName $target -ea stop $ret.psbase.Scope.Options.EnablePrivileges = $true $ret | Invoke-WmiMethod -Name $Command if ($ret.returnvalue -eq 2) { $Status = "fail" $Reason = "$Command not successfull: Access denied" } elseif ($ret.returnvalue -eq 0) { $Status = "pass" $Reason = "$Command Successfully executed" } else { $Status = "fail" $Reason = "$Command not successfull" } } catch [System.UnauthorizedAccessException] { $Status = "fail" $Reason = "$Command not successfull: access denied" } } else { $Status = "fail" $Reason = "Started with -WhatIf" } } elseif ($Method -match "winrm") { $Status = "fail" $Reason = "method not implemented yet" } elseif ($Method -match "external") { Write-Verbose "Using external tools" Write-Verbose "BinPath: $BinPath" if (!(Test-Path -Path "$BinPath\psshutdown.exe")) { $Status = "fail" $Reason = "Binary psshutdown not found." } else { # RemoteRegistry is needed for PsExec try { if (!$IsLocalhost -and !$NoRemoteRegistry -or (!$IsLocalhost -and $WhatIfPassed)) { $err = Enable-RemoteRegistry -Method external -ComputerName $target -WhatIf:$WhatIfPassed -OnlineCheck:$false -Credential:$Credential $returnobject += $err $srr = Start-Service -ComputerName $target -Method external -Name "RemoteRegistry" -WhatIf:$WhatIfPassed -OnlineCheck:$false -Credential:$Credential $returnobject += $srr $RemoteRegistryStarted = ($srr.status -match "pass") } else { # assume RemoteRegistry is already started $RemoteRegistryStarted = $true } } catch { $Reason = "Error while enabling RemoteRegistry" $Status = "fail" } $RemoteRegistryStarted = $true if ($RemoteRegistryStarted -or $WhatIfPassed) { if ($pscmdlet.ShouldProcess($target, "$Command")) { $Param = "" if ($Command -match "reboot") { $Param = "-r" } if ($target -match "localhost") { $proc = Start-Process psshutdown.exe -commandline "-accepteula -nobanner -f -t 1 $Param" } else { $proc = Start-Process psshutdown.exe -commandline "-accepteula -nobanner -f -t 1 $Param \\$target" } if ($proc.ExitCode -eq 0) { Write-Verbose "Successfully executed binary on $target" } else { Write-Verbose "Error while running binary on $target" Write-Verbose "stdout" Write-Verbose $proc.stdout write-verbose "stderr" write-verbose $proc.stderr } # todo check stdout/stderr from psshutdown if ($proc.stdout) { if ($proc.stdout -match "erfolgreich" -or $proc.stdout -match "successfull") { $Status = "pass" $Reason = "Executed $Command" } else { $Status = "fail" $Reason = "Fail: $($proc.stdout), $($proc.stderr)" } } # stdout has result else { $Status = "fail" $Reason = "Fail: $($proc.stdout), $($proc.stderr)" } } # whatif else { $Status = "pass" $Reason = "Not executed - started with -WhatIf" } } #RemoteRegistry started else { $Status = "fail" $Reason = "Error while enabling RemoteRegistry" } try { if (!$IsLocalhost -and !$NoRemoteRegistry -and $RemoteRegistryStarted -or (!$IsLocalhost -and $WhatIfPassed)) { Write-Verbose "Cleanup RemoteRegistry" $srr = Stop-Service -ComputerName $target -Method external -Name "RemoteRegistry" -WhatIf:$WhatIfPassed -OnlineCheck:$false $returnobject += $srr $drr = Disable-RemoteRegistry -Method external -ComputerName $target -WhatIf:$WhatIfPassed -OnlineCheck:$false $returnobject += $drr } } # disable RemoteRegistry catch { $Reason = "Error while disabling RemoteRegistry" $Status = "fail" } } # binary found } #UseExternal } # host online $returnobject += New-PowerSponseObject -Function $Function -Status $Status -Reason $Reason -Arguments $Arguments -ComputerName $target } #foreach target } # parameters ok $returnobject Write-Verbose "Leaving $Function" } |