Request Computer Name before running script - powershell

I have a script that stops a service then renames a folder on the local computer, i would like to be able to make a run remotely by asking the command executer to enter the machine name of where it would like to run the script then execute.
try {
Stop-service wuauserv -force
} catch {
Write-error "Unable to stop the service WUAUSERV"
start-sleep -seconds 5
exit
}
try {
Rename-Item "C:\Windows\SoftwareDistribution" "C:\Windows\SoftwareDistribution.old" -force
} catch {
Write-error "Unable to rename the folder :("
start-service wuauserv
start-sleep -seconds 5
exit
}
start-service wuauserv

I would probably have the script take a parameter by adding this at the top
Param(
[Parameter(Mandatory)][string]$ComputerName
)
The Mandatory value will prompt the user to enter a value if it was not supplied.
Alternatively if you really want to manually ask the user you can use this:
$ComputerName = Read-Host "ComputerName"
This will also prompt the user to enter a variable.
Then use Invoke-Command to run your logic on the remote computer
Invoke-Command -ComputerName $ComputerName -ScriptBlock {
# Your code here..
}
Edit:
After your update, I notice you terminate the script by calling exit. I would advise you to use return instead. If someone runs this script from the commandline the script will kill the terminal, which is quite annoying.
Edit2: Here is a complete working example, with my recommendations:
Param(
[Parameter(Mandatory)][string]$ComputerName
)
Invoke-Command -ComputerName $ComputerName -ScriptBlock {
try {
Stop-Service wuauserv -Force
} catch {
Write-error "Unable to stop the service WUAUSERV"
Start-Sleep -Seconds 5
return
}
try {
Rename-Item "C:\Windows\SoftwareDistribution" "C:\Windows\SoftwareDistribution.old" -Force
} catch {
Write-error "Unable to rename the folder :("
Start-Service wuauserv
Start-Sleep -Seconds 5
return
}
Start-Service wuauserv
}

Related

Powershell nested for loop to restart services

My goal is to loop through all devices , stop a specific service for all of those devices ( in this case, IntenAudioService), then go kill speciifc tasks realted to that service ( let's just say task IntelX and task IntelY, if they exist)
Then just loop through again and re-start those services. can this be done all in 1 for loop? Is the syntax correct?
$devices= <<user can populate devices in this object. DeviceName or deviceID??>>
>Foreach ($device in $devices){
Invoke-Command -ComputerName $device {
net-stop IntelAudioService
taskkill /IM IntelX.exe /F
net start IntelAudioService
}
}
What if I wanted to also set a service for each device? Something like this?
foreach ($device in $devices){
Invoke-Command -ComputerName $device {
Set-Service -Name BITS -StartupType Automatic
}
}
Try with this, note that you can Invoke-Command to multiple hostnames at the same time. You can also create a New-PSession with multiple computers at the same time.
$ErrorActionPreference = 'Stop'
$devices = 'Hostname1','Hostname2'
$serviceName = 'IntelAudioService' # This can be an array
$processName = 'IntelX' # This can be an array
# Note: Looping through the devices an attempting to establish a
# PSSession like below is good if you're not sure if the remote host
# is up or if the device name is the right one, etc. Using a Try {} Catch {}
# statement in this case will let you know if you couldn't connect with a
# specific remote host and which one.
# You can also simply do: $session = New-PSSession $devices without
# any loop which will be a lot faster of course, however,
# if you fail to connect to one of the remote hosts
# you will get an error and the the PSSession cmdlet will stop.
$session = foreach($device in $devices)
{
try
{
New-PSSession $device
}
catch
{
Write-Warning $_
}
}
Invoke-Command -Session $session -ScriptBlock {
Get-Service $using:serviceName | Stop-Service -Force -Verbose
Get-Process $using:processName | Stop-Process -Force -Verbose
Start-Service $using:serviceName -Verbose
# Set-Service -Name $using:serviceName -StartupType Automatic
}
Remove-PSSession $session

canceling get-credentials in loop

I am working on developing PowerShell script to automate a task on a remote server by using Invoke-Command with WinRM.
The script will take the server IP, test WinRM and "Get-Credential" cmdlet to establish session and use Invoke-Command to run another script on remote server. I have made significant progress of what I want to achieve, however, I am having trouble on how to setup the code so that when I press the "Cancel" or "X" button on Get-Credential prompt it should abort the script and return to the regular PowerShell command line prompt.
Below is what I have so far, I have erased the comments and description of the code to keep the number of words less in here.
function SS
{
Add-Type -AssemblyName System.Windows.Forms
$BInput = [System.Windows.Forms.MessageBox]::Show('Do you want to proceed?', 'Confirmation',[System.Windows.Forms.MessageBoxButtons]::YesNo)
switch ($BInput)
{
"Yes" {
while ($true)
{
$server=Read-Host "Enter Server IP Address"
set-item -Path WSMan:\localhost\Client\TrustedHosts -Value "$server" -Force
if(Test-WSMan -ComputerName $server -ErrorAction SilentlyContinue)
{
Write-Host "$server is accessible, enter credentials to connect"
while ($true)
{
$creden=Get-Credential -Message "Please enter the server credentials that you want to connect"
$serversession = New-Pssession -ComputerName $server -Credential $creden -ErrorAction SilentlyContinue
if(-not($serversession))
{
write-warning "Credentials are not valild, please try again"
}
else
{
write-host "$server is connected, starting the workflow ......"
Invoke-Command -Session $serversession -FilePath "C:\Temp\XXX.ps1"
}
}
Break
}
else
{
write-host "Windows Remote Management (WinRM) protocol is not running, please check service and confirm."
}
}
Get-Pssession | Remove-PSSession
}
"No" {
Break
}
}
}
I understand I have to apply the changes / logic after this line
$creden=Get-Credential -Message "Please enter the server credentials that you want to connect"
But can't seem to find it yet. I looked online and have taken different approaches but no success so far. I would like to have opinions or recommendations on how to tackle this, appreciate your help.
Thanks
What i'm seeing is that you may be thinking too much into it. A simple if statement should do the trick, try:
$creden=Get-Credential -Message "Please enter the server credentials that you want to connect"
if(!$creden){break}
Continuing from my comment.
Try this refactor of your use case.
Point of note: Note fully tested since I do not have an environment at this time to test.
Function Start-WorkFlow
{
<#
.Synopsis
Execute a workflow
.DESCRIPTION
Sets up a WinRM session to a remote host to execute the defined workflow
.EXAMPLE
Start-WorkFlow
.EXAMPLE
swf
.INPUTS
Remote host IPAddress
Remove host credentials
.OUTPUTS
Resutls of teh workflow
.NOTES
V 0.0.1 - Prototype script. Clean-Up before production use
.COMPONENT
Stand-alone script
.ROLE
Administrative actions
.FUNCTIONALITY
Implemetned error logic for each code block
Restrict the user input to only be a proper IPAddress
Validate TCPIP state
Validate WSman state
Establish a new session
Process workflow
Exit session
#>
[cmdletbinding(SupportsShouldProcess)]
[Alias('swf')]
Param
(
)
If ((Read-Host -Prompt 'Do you want to proceed: [Yes/No]') -eq 'No' )
{Break}
Else
{
Do {$RemoteServerIPAddress = (Read-Host -Prompt 'Enter Server IP Address')}
Until ($RemoteServerIPAddress -match "^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$")
Get-ChildItem -Path 'WSMan:\localhost\Client\TrustedHosts'
Try
{
(Test-Connection -ComputerName $RemoteServerIPAddress -Count 1 -ErrorAction Stop).IPV4Address
# Set-Item -Path 'WSMan:\localhost\Client\TrustedHosts' -Value $RemoteServerIPAddress -Force
Get-ChildItem -Path 'WSMan:\localhost\Client\TrustedHosts'
Try
{
Test-WSMan -ComputerName $RemoteServerIPAddress -ErrorAction Stop
"$RemoteServerIPAddress is accessible, enter credentials to connect"
Do
{
$Creds = $null
$CredMesssage = 'Please enter the remote server credentials that you want to connect.'
$CredMesssage = "$CredMesssage If credentials are not valid, you will be prompted to re-enter them."
$Creds = Get-Credential -Message $CredMesssage
if(-Not $creds)
{
Write-Warning -Message 'Credential request cancelled.'
Start-Sleep -Seconds 3
Exit
}
$NewPSSessionSplat = #{
ComputerName = $RemoteServerIPAddress
Credential = $Creds
Name = 'RemoteSessionName'
ErrorAction = 'Stop'
}
New-PSSession $NewPSSessionSplat
}
Until (Get-PSSession -Name 'RemoteSessionName')
"$RemoteServerIPAddress is connected, starting the workflow ......"
Invoke-Command -Session $RemoteServerSession -FilePath 'C:\Temp\XXX.ps1'
}
Catch
{
Write-Warning -Message 'Session connection results:'
$PSitem.Exception.Message
}
Finally
{
Get-PSSession |
Remove-PSSession -ErrorAction SilentlyContinue
}
}
Catch
{
Write-Warning -Message "
The remote server $RemoteServerIPAddress is not available
Exiting the session."
Start-Sleep -Seconds 3
Exit
}
}
}
Start-WorkFlow

How can i check if the task is running on my User?

$a = 1
while($a = 1){
$explorer = Get-Process explorer.exe -ErrorAction SilentlyContinue -IncludeUserName
if ($explorer.Administrator) {
}
else{
start explorer
}
timeout 10
}
I need to get the task from my user... Any ideas.
We are in a project on one computer. My friend is connected with Remotedesktop. We troll each other with closing the explorer etc. I want to restart the explorer after he closed it. His is still running. Thats the problem.
Try Get-Process with -IncludeUserName
$explorer = Get-Process explorer -ErrorAction SilentlyContinue -IncludeUserName
$explorer.UserName
But the IncludeUserName parameter requires elevated user rights. Run script as Administrator.
UPD. This will help you with process start if there is no explorer running with your username. Replace put_your_username_here to your username.
while($true){
$flagToStart = $true
$explorersArray = Get-Process "explorer" -ErrorAction SilentlyContinue -IncludeUserName
foreach($explorerProc in $explorersArray) {
if ($explorerProc.UserName -like "*put_your_username_here") {
Write-Output "No need to restart"
$flagToStart = $false
}
}
if($flagToStart -eq $true) {
Start-Process -FilePath "explorer"
}
Start-Sleep -Seconds 5
}

How to fix ADSync exception error when starting Delta sync with powershell

When I try to kick off a Delta Sync through a pssession a error is thrown. If I run the commands one line at a time it runs perfectly fine.
Enter-PSSession server_name
Get-Module ADSync | Import-Module
Start-ADSyncSyncCycle -PolicyType Delta
Exit-PSSession
I expect it to start the Sync but just get the error:
'Microsoft.DirectoryServices.MetadirectoryServices.UI.PropertySheetBase.UIUtils'
threw an exception.
I usually perform a Start-ADSyncSyncCycle through a helper function that detects if the ADSyncScheduler is suspended and also detects if there maybe already a sync cycle in progress. Without watching for these things you may receive errors.
function Start-SyncCycle {
[CmdletBinding()]
param(
[Parameter(Mandatory = $false, Position = 0)]
[ValidateSet('Delta','Initial')]
[string]$PolicyType = 'Delta'
)
# test if the ADSyncScheduler is not suspended
$scheduler = Get-ADSyncScheduler
if ($scheduler.SchedulerSuspended) {
# SchedulerSuspended is set during an upgrade to temporarily block the scheduler from running.
# When this property is $true, running Start-ADSyncSyncCycle wil result in error:
# System.InvalidOperationException: Scheduler is already suspended via global parameters.
Set-ADSyncScheduler -SchedulerSuspended $false
}
# test if a scheduled synchronization is already running
if ($scheduler.SyncCycleInProgress) { # or use: if (Get-ADSyncConnectorRunStatus) { ... }
Write-Warning "A sync is already in progress. Please try again later."
}
else {
Write-Host "Initializing Azure AD $PolicyType Sync..." -ForegroundColor Yellow
try {
Start-ADSyncSyncCycle -PolicyType $PolicyType -ErrorAction Stop | Out-Null
Write-Host "Waiting for Sync to start.."
# give the Sync Connector some time to start up (10 seconds should be enough)
Start-Sleep -Seconds 10
Write-Host "Waiting for Sync to finish.."
While(Get-ADSyncConnectorRunStatus) {
Write-Host "." -NoNewline
Start-Sleep -Seconds 5
}
Write-Host
Write-Host "Azure AD $PolicyType Sync has finished." -ForegroundColor Green
}
catch {
Write-Error $_.Exception.Message
}
}
}
You use the function like this:
$cred = Get-Credential -UserName "your.username#yourdomain.com" -Message "Please enter credentials for yourdomain.com"
Invoke-Command -ComputerName $AzureConnectServer -ScriptBlock ${function:Start-SyncCycle} -Credential $cred
Hope that helps
The solution that ended up working out for me was to invoke the command rather then enter a pssession. I am not sure why this works, but it does.
$cred = Get-Credential
Invoke-Command -ComputerName server_name -Credential $cred -ScriptBlock{
Import-Module -Name "C:\Program Files\Microsoft Azure AD Sync\Bin\ADSync"
Start-ADSyncSyncCycle -PolicyType Delta
}

Exit not Exiting in invoke-command in remote ps session

I have a Function invokes a command that starts a new ps session on a remote server. The invoke command has an Exit clause however this is not exiting?
Function CreateID{
Invoke-Command -Session $Script:sesh -ScriptBlock{
Set-Location c:\
Import-Module ActiveDirectory
Try
{
If (Get-ADGroupMember "$Using:IDGroup" | Where-Object Name -match
"$Using:Computer")
{
Write-Host "Already in $using:IDGroup Exiting Script"
Disconnect-PSSession -Session $Script:sesh
Exit-PSSession
Exit
}
}
Catch
{ }
Write-Host "Did not Exit"
}
}
The Get-AD command works fine so where it should not display "did not exit" it does - how can i exit from a scriptblock in a remote ps session?
I am trying the disconnect session and Exit-pssession to see if they would do the same as simply exit but none of those are working.
I have also tried Break and no luck.
Ok so i figured this out - the ps session and invoke-command are red herrings. The basis of this is that you cannot Exit a Try/Catch statement.
i had to do this to get it to work - now it Exits. I just cannot use a Try/ Catch - if anyone knows how to exit a Try/Catch let me know!
#Try
#{
If (Get-ADGroupMember "$Using:IDGroup" | Where-Object Name -match
"$Using:Computer")
{
Write-Host "Already in $using:IDGroup Exiting Script"
Disconnect-PSSession -Session $Script:sesh
Exit-PSSession
Exit
}
#}
#Catch
#{ }
I don't know if this works for PSSession or not, and I don't have an environment to test it, but you can use this to exit powershell within a try catch
[Environment]::Exit(0)
Try/Catch should work in an invoke-command.
I don't usually invoke-commands to sessions, rather I use -ComputerName.
This worked fine for me:
invoke-command -ComputerName "MyDomainController" -ScriptBlock {
try { get-aduser "ValidUser" } catch { "doh!" }
}
I just tried this as well and it also worked:
$sess1 = New-PSSession -ComputerName MyDomainController
invoke-command -Session $sess1 -ScriptBlock { try { get-aduser "ValidUser" } catch { "doh!" } }
If I change either of those "ValidUser" values to invalid users I see the "doh!" as well.
Perhaps it's because you're trying to end the session from within the session.
You should deal with the output of the invoke-command or the function and then handle the session based on that.
Like using my lame example...
$sess1 = New-PSSession -ComputerName MyDomainController
$DoStuff = invoke-command -Session $sess1 -ScriptBlock { try { get-aduser "ValidUser" } catch { "doh!" } }
If ($DoStuff -eq "doh!") { Remove-PSSession $sess1 } else { $DoStuff }