Powershell with Shutdown command error handling - powershell

My shutdown script using the Shutdown -R command to do a mass reboot of machines. If the Shutdown -R throws a error like "RPC Service Unavailable, or access denied" I can't catch it or just don't know how to. Can someone help? I don't want to use Restart-Computer in powershell since you can't delay the reboot and can't add comments.
foreach($PC in $PClist){
ping -n 2 $PC >$null
if($lastexitcode -eq 0){
write-host "Rebooting $PC..." -foregroundcolor black -backgroundcolor green
shutdown /r /f /m \\$PC /d p:1:1 /t 300 /c "$reboot_reason"
LogWrite "$env:username,$PC,Reboot Sent,$datetime"
} else {
write-host "$PC is UNAVAILABLE" -foregroundcolor black -backgroundcolor red
LogWrite "$env:username,$PC,Unavailable/Offline,$datetime"
}
}

If PowerShell Remoting is enabled on $PC something like this might work:
Invoke-Command -Computer $PC { shutdown /r /f /d p:1:1 /t 300 /c $ARGV[0] } `
-ArgumentList $reboot_reason
The -Computer option takes an array of names/IPs.
If you want to stick with your approach and just catch errors from shutdown.exe, evaluate $LastExitCode after the command:
shutdown /r /f /m \\$PC /d p:1:1 /t 300 /c "$reboot_reason" 2>$null
if ($LastExitCode -ne 0) {
Write-Host "Cannot reboot $PC ($LastExitCode)" -ForegroundColor black `
-BackgroundColor red
} else {
LogWrite "$env:username,$PC,Reboot Sent,$datetime"
}
2>$null suppresses the actual error message, and the check on $LastExitCode triggers the success/failure action.

Related

Powershell: IF, TRY and CATCH block in powershell script

I am using try and catch block inside IF condition, but I am not getting the desired results.
If (Test-Path -Path "$env:DigiCertificate"){
try {
signtool sign /f $env:DigiCertificate /v /t http://timestamp.sectigo.com /a /fd SHA256 /p $env:DigicertsPassword $MediaFolderPath\scripts\*.ps1 $MediaFolderPath\tools\*.exe
}catch
{
Write-Host "required certificate not found to sign" -ForegroundColor Yellow
Write-Host "$($_.Exception.Message)." -ForegroundColor Red
exit 1
}
}
In the above code I am expecting the IF condition should check for the -Path and it should fail if it does not find the DigiCertificate. Apart from try and catch block even IF condition should work, but I am trying to do it but I am missing something.

Powershell script to remotely change registry setting based on version or installation path of program

I have a Powershell script that remotely adds a registry setting to computers on the network depending on which version of MS Office they have installed. At the moment, the script looks in c:\Program Files\Microsoft Office, then checks to see there is either an Office15 or Office16 folder than applies the appropriate reg entry. The problem is that I've discovered that some assets on the network also have the 32 bit version of MS Office, so their installations are going to be in c:\Program Files (x86)\Microsoft Office (\Office15 or \Office16), even though the reg entries added will be the same.
At the moment, I can't figure out how to make the script look for the two possible installation locations it could be in first (Program Files (x86)\Microsoft Office or Program Files\Microsoft Office), before determining what to do next (If ($Ver.name -Contains 'Office16')) etc.
The script:
$Asset = Read-Host "Please enter the asset number of the machine"
$User = Read-Host "Please enter the username of the users account"
$SID = Get-ADUser -Identity $User
If (Test-Connection $Asset -ErrorAction SilentlyContinue){
$Ver = Get-ChildItem \\$Asset\c$\Program Files\Microsoft Office
If ($Ver.name -Contains 'Office16') {
Write-Host ""
$RegPath = \\$($Asset)\HKEY_USERS\$($SID.sid)\Software\Microsoft\Office\16.0\Outlook\Preferences
REG ADD $RegPath /f /v DelegateSentItemsStyle /t REG_DWORD /d 1
} ElseIf ($Ver.name -Contains 'Office15') {
Write-Host ""
$RegPath = \\$($Asset)\HKEY_USERS\$($SID.sid)\Software\Microsoft\Office\15.0\Outlook\Preferences
REG ADD $RegPath /f /v DelegateSentItemsStyle /t REG_DWORD /d 1
} Else {
Write-Host ""
Write-Host "Unable to determine the version of Office installed." -ForegroundColor Red
}
} Else {
Write-Host ""
Write-Host "Unable to contact the machine. Please ensure you have enter the correct asset number" -ForegroundColor Green
}
pause
Any ideas appreciated.
Cheers.
Get-ChildItem can look into an array of "paths", hence you can store both known paths for Microsoft Office in an array and search for both of them. I've changed the order of the condition statements a bit, I personally find this more straight forward:
$Asset = Read-Host "Please enter the asset number of the machine"
$User = Read-Host "Please enter the username of the users account"
$SID = Get-ADUser -Identity $User
$paths = #(
"\\$Asset\c$\Program Files (x86)\Microsoft Office"
"\\$Asset\c$\Program Files\Microsoft Office"
)
If (-not (Test-Connection $Asset -Quiet)) {
Write-Warning "Unable to contact the machine. Please ensure you have enter the correct asset number"
break
}
$Ver = Get-ChildItem $paths -ErrorAction SilentlyContinue -ErrorVariable Errors
if(-not $Ver) {
Write-Warning "Failed to retrieve paths on $Asset"
$Errors.Exception.Message
break
}
if($Ver.Name -Contains 'Office16') {
$RegPath = "\\$Asset\HKEY_USERS\$($SID.sid)\Software\Microsoft\Office\16.0\Outlook\Preferences"
REG ADD $RegPath /f /v DelegateSentItemsStyle /t REG_DWORD /d 1
}
elseif($Ver.Name -Contains 'Office15') {
$RegPath = "\\$Asset\HKEY_USERS\$($SID.sid)\Software\Microsoft\Office\15.0\Outlook\Preferences"
REG ADD $RegPath /f /v DelegateSentItemsStyle /t REG_DWORD /d 1
}
else {
Write-Warning "Unable to determine the version of Office installed."
}

Powershell: Call Debug Analyzer cdb.exe as Process

i need to call the cdb.exe as a Process to check to kill the process after a few seconds.
Some Dumps cannot be analyzed so i have to do an other call.
Here you can see my code. But it doesn't work. The cdb.exe is not started correctly and i am not getting the output file.
Do you have some advises for me?
The call "before" implementing the process part starts the cdb.exe
$maximumRuntimeSeconds = 3
$path = "C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\cdb.exe"
$process = Start-Process -FilePath $path "-z $unzippedFile.FullName, -c `".symfix;.reload;!analyze -v; q`""
try {
$process | Wait-Process -Timeout $maximumRuntimeSeconds -ErrorAction Stop > $outputFile
Write-Warning -Message 'Process successfully completed within timeout.'
}
catch {
Write-Warning -Message 'Process exceeded timeout, will be killed now.'
$process | Stop-Process -Force
}
# call before implementing Process
& "C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\cdb.exe" -z $unzippedFile.FullName -c ".symfix;.reload;!analyze -v; q" > $outputFile
-Passthru was needed to make Wait-Process work.
I think you also need to look at how the double quoted string is expanding. I think $UnzippedFIle.Fullname might be adding a literal ".FullName" at the end of the actual fullname of the zip file. I don't have your environment, but the rudementary tests I've done show that. Try packing it in a sub-expression like:
"-z $($unzippedFile.FullName), -c `".symfix;.reload;!analyze -v; q`""
Let me know how that goes. Thanks.
C:\>dir /b ok.txt
File Not Found
C:\>type dodump.ps1
$path = "C:\Program Files\Windows Kits\10\Debuggers\x86\cdb.exe"
$process = Start-Process -PassThru -FilePath $path -ArgumentList "-z `"C:\calc.DMP`"" ,
"-c `".symfix;.reload;!analyze -v;q`"" -RedirectStandardOutput c:\\ok.txt
try {
$process | Wait-Process -Timeout 100 -ErrorAction Stop
Write-Host "Process finished within timeout"
}catch {
$process | Stop-Process
Write-Host "process killed"
}
Get-Content C:\ok.txt |Measure-Object -Line
C:\>powershell -f dodump.ps1
Process finished within timeout
Lines Words Characters Property
139

Executing a Batch file on remote server from powershell command

I'm currently trying to implement the functionality mentioned in this question, but I haven't had any success. I'm trying to run this on a TeamCity server to copy some files and then run a batch file. The robocopy works perfectly but the execution for the Invoke-Command seems to fail but it doesn't throw any error in any of the ways I've tried.
This is my code:
$deploymentComputerName = 'server.name.com'
$robocopyPath = 'C:\Windows\System32\robocopy.exe'
try {
$deploymentShare = "\\" + $deploymentComputerName + "\folder"
$deploymentPackageDirectory = 'c:\local\route'
$invokeRoute = "C:\Route\batchFile.bat"
&$robocopyPath /E /PURGE $deploymentPackageDirectory $deploymentShare /r:0 /XF "LibSassHost.dll" "LibSassHost.Native-64.dll" "libsass.dll"
Write-Host "Attempting to run it with the FIRST method"
Invoke-Command -ComputerName $deploymentComputerName -ScriptBlock {Invoke-Expression -Command:"cmd.exe /c '$invokeRoute'"}
Invoke-Command -ComputerName $deploymentComputerName -ScriptBlock {Invoke-Expression -Command:"cmd.exe /c $invokeRoute"}
Write-Host "Attempting to run it with the SECOND method - " $invokeRoute
Invoke-Command -ScriptBlock { "$deploymentShare\batchFile.bat" } -ComputerName $deploymentComputerName
Write-Host "Finished trying to run the methods"
} catch {
Write-Host "Error running powershell file"
}

Powershell : How to check the good execution of a batch file on a remote computer using invoke-command

here is the relevant code :
$op=invoke-command -computername test -scriptblock{
& "cmd.exe" /c c:\temp\psbatch.bat 2>&1
$LASTEXITCODE
}
if ($op - eq 0) {echo "success"}
else {echo "failure"}
The problem is that if my batch echo something, the output will be capture in $op so it will not be equal to 0.
How to handle that ?
You can try something like this:
$op=invoke-command -computername test -scriptblock{
& "cmd.exe" /c c:\temp\psbatch.bat 2>&1
$LASTEXITCODE
}
if (#($op)[-1] -eq 0) {echo "success"}
else {echo "failure"}
Force the result to an array, and then test just the last line, which will be the last exit code. Anything echoed before that will be ignored.