How to create in Powershell Menu insight of Menu - powershell

I came up with a little helpful script to help monitor and control Services on the remote servers:
do {
$srv = Read-Host 'What is your ServerName?'
$srvs = Read-Host 'What is ServiceName?'
$userMenuChoice = Read-Host -Prompt "
`n1. ServiceList
`n2. Service Status.
`n3. Stop Service.
`n4. Start Service.
`n5. Exit
`nPlease Select Operation"
switch($userMenuChoice){
1{Get-Service -ComputerName $srv | select -property name,starttype}
2{gsv -cn $srv -Name "$srvs*" | Out-String}
3{Get-Service -Name "$srvs*" -ComputerName $srv | Stop-Service}
4{Get-Service -Name "$srvs*" -ComputerName $srv | Start-Service}
5{exit}
}
} while ( $userMenuChoice -ne 4 )
Please, help me figure out how I can get prompt to keep the same server and service ( or NOT) and continue use same menu.
Something like: Before getting to MENU $userMenuChoice it will ask if I want to keep the same server Y/N (Y Default) Do you want to keep the same Service Y/N (Y Default)...
Also How I Can clear screen before Proceeding to the next Menu.
Thank you!

This is called Scope.
Variables created in the block can only survive in that iteration of the block.
$A = "Hello"
While(1 -eq 1){
$B = Read-Host 'Type Name?'
"$A $B"
}
$A will forever be Hello because it was made outside the scope of While
$B will change forever because its inside the Scope of While.
(Also because each time you call while you are replacing $B with read-host anyways)
What you want to do is give a option on the ServerName and place a variable outside the scope of while.
$CurrentServer = $Null
$CurrentService = $Null
do {
if(!($CurrentServer) -or $(Read-Host 'Change Server (Y,N)?') -eq "Y"){
$CurrentServer = Read-Host 'What is your ServerName?'
}
if(!($CurrentService) -or $(Read-Host 'Change Service (Y,N)?') -eq "Y"){
$CurrentService = Read-Host 'What is ServiceName?'
}
$userMenuChoice = Read-Host -Prompt #"
1. ServiceList
2. Service Status.
3. Stop Service.
4. Start Service.
5. Exit
Please Select Operation
"#
switch($userMenuChoice){
1{Get-Service -ComputerName $CurrentServer | select -property name,starttype}
2{gsv -cn $CurrentServer -Name "$CurrentService*" | Out-String}
3{Get-Service -Name "$CurrentService*" -ComputerName $CurrentServer | Stop-Service}
4{Get-Service -Name "$CurrentService*" -ComputerName $CurrentServer | Start-Service}
5{exit}
}
} while ( $userMenuChoice -ne 4 )
The line
if(!($CurrentServer) -or $(Read-Host 'Change Server (Y,N)?') -eq "Y"){}
Allows for you to Change server and service if you wanted to But also allows you to skip it if needed.
It is saying if $CurrentServer is empty OR if $CurrentServer has value Ask Change Server, If Change Server is Y then run if

This seems too easy. Put the Read-Host cmdlets outside of the loop.
$srv = Read-Host 'What is your ServerName?'
$srvs = Read-Host 'What is ServiceName?'
do {
$userMenuChoice = Read-Host -Prompt "
`n1. ServiceList
`n2. Service Status.
`n3. Stop Service.
`n4. Start Service.
`n5. Exit
`nPlease Select Operation"
switch($userMenuChoice){
1{Get-Service -ComputerName $srv | select -property name,starttype}
2{gsv -cn $srv -Name "$srvs*" | Out-String}
3{Get-Service -Name "$srvs*" -ComputerName $srv | Stop-Service}
4{Get-Service -Name "$srvs*" -ComputerName $srv | Start-Service}
5{exit}
}
} while ( $userMenuChoice -ne 4 )

Related

Powershell Script outputs are merged instead of separated individually

I made this script to ping a computer name and if it's pingable, to return the username of the logged on user and if the user of the script so desires, a list of all the installed programs and a list of the installed printers the user is using.
When I run the script it returns the username and requires the users' input if they want to see the installed programs, the user answers Y or N. It asks the user afterwards if they want to the list of printers.
The script then gives an output of both the list of programs & printers as one answer.
My problem is that I would like the script to ask if the user wants the programs list, then to output the programs list, then prompt if the user wants the printers list, then output the printer list.
I have no idea how to go about this and have searched and experimented and have found no solution.
Any help or advice would be greatly appreciated :)
Apologies for the long post
# This script shows who is currently logged on to a machine
$PCNAME = Read-Host "Please enter computer name"
Write-Host "Pinging computer name..."
# If the computer responds to ping then the user name will be displayed
If (Test-Connection -ComputerName $PCNAME -Quiet)
{
$User = Get-WmiObject Win32_ComputerSystem -ComputerName $PCNAME | Select-Object -ExpandProperty UserName
$Time = Get-Date -DisplayHint Time
Write-Host ""
$CurUser = Write-Host "The current user logged in to $PCNAME is $User at $Time" -ForegroundColor Green
Write-Host ""
}
#PROGRAMS
$Programs = Read-Host "Would you like to see what programs $User has installed? Enter Y or N"
If ($Programs -eq "Y") {
Write-Host ""
Write-Host "Retrieving list of installed programs..."
Write-Host ""
Get-WmiObject -ComputerName $PCNAME -Class Win32_Product | sort-object Name | select Name
}
ElseIf ($Programs -ne "Y" -and $Programs -eq "N") {
Write-Host ""
Write-Host "Will not retrieve list of installed programs."
}
#PRINTERS
$Printers = Read-Host "Would you like to see the pinters that $User is using? Enter Y or N"
If ($Printers -eq "Y") {
Write-Host ""
Write-Host "Getting printers..."
Write-Host ""
# Collect port names and host addresses into hash table
$hostAddresses = #{}
Get-WmiObject Win32_TCPIPPrinterPort -ComputerName $PCNAME | ForEach-Object {
$hostAddresses.Add($_.Name, $_.HostAddress)
}
Get-WmiObject Win32_Printer -ComputerName $PCNAME | ForEach-Object {
New-Object PSObject -Property #{
"Name" = $_.Name
"DriverName" = $_.DriverName
"HostAddress" = $hostAddresses[$_.PortName]
}
}
}
ElseIf ($Printers -ne "Y" -and $Printers -eq "N") {
Write-Host ""
Write-Host "Could not get printers"
Write-Host ""
}
Else
{
Write-Host ""
Write-Host "Could not ping $PCNAME at $Time" -ForegroundColor DarkCyan
}
Write-Host ""
#$EndPrompt = ( Read-Host -Prompt "Press Enter to finish" )
There's better ways of doing this overall, but the simplest way to add this is:
#PROGRAMS
$Programs = Read-Host "Would you like to see what programs $User has installed? Enter Y or N"
If ($Programs -eq "Y") {
Write-Host ""
Write-Host "Retrieving list of installed programs..."
Write-Host ""
$Installed = Get-WmiObject -ComputerName $PCNAME -Class Win32_Product | sort-object Name | select Name
$Installed | Out-Host
}
ElseIf ($Programs -ne "Y" -and $Programs -eq "N") {
Write-Host ""
Write-Host "Will not retrieve list of installed programs."
}

Trying ru script in the loop to see if services on Remote Server (s) is running

Originally I had a script:
Do {
Get-Date
Write-Output "SERVER01";
gsv -cn SERVER01 -Name Dm* |out-string
Write-Output "SERVER02";
gsv -cn SERVER02 -Name Dm* |out-string
sleep 60
}
while ($true)
I am trying to make Server(s) name and service a variable
Do {
Get-Date
$name = Read-Host 'What is your ServerName?'
$srv = Read-Host 'What is ServiceName?'
write-host $name
gsv -cn $name -Name $srv |out-string
sleep 60
}
Please help me to make it work.
There's nothing wrong with your code other than you assumedly only want to prompt for the server name and service name once and then check them repeatedly. In which case, move your read-host lines to before the Do loop:
$name = Read-Host 'What is your ServerName?'
$srv = Read-Host 'What is ServiceName?'
Do {
Get-Date
Write-Host $name
gsv -cn $name -Name "$srv*" | Out-String
Sleep 60
}
while ($true)
I've also added the wildcard * character back into your retrieval of the services, per your original script, so that you can return services based on a partial name.

Powershell Read-host input from CSV

Im trying to get this script to work by instead of me manually inputing sysnames that I can put the servers into csv and script it and give an output of results
It just sits at the prompt waiting for manual input
$csvpath = E:\Tsm.csv
$SvcName = '*tsm*scheduler*'
$dataset = import-csv -path $csvpath
$row = ($dataset | where{$_.hostname -eq $SysName})
$SysName = Read-Host -prompt "Enter the target computer name: "
$Tsm = Get-Service -ComputerName $SysName | Where {$_.name -Like $SvcName}
Write-Host "Service :" $Tsm.DisplayName
Write-Host "Status :" $Tsm.Status
Write-host "Start Type :" $Tsm.StartType
If ($Tsm.StartType -ne 'Automatic')
{
Write-Host "Setting service startup type to Automatic."
Set-Service -InputObject $Tsm -StartupType Automatic
}
If ($Tsm.Status -ne 'Running')
{
Write-Host "Starting the service."
Start-Service -InputObject $Tsm
}
$Tsm2 = Get-Service -ComputerName $SysName | Where {$_.name -Like $SvcName}
Write-Host "Service :" $Tsm2.DisplayName
Write-Host "Status :" $Tsm2.Status
Write-host "Start Type :" $Tsm2.StartType
Export-Csv C:\TestOutput.csv$csvpath = E:\Tsm.csv
There are many ways to get what you want. Basically you shouldn't be using Read-Host, or only use it when you want the prompt and manual waiting.
A couple of points:
# this line uses the $SysName variable, which is asked for in the next line.
# so it will not work correctly.
$row = ($dataset | where{$_.hostname -eq $SysName})
# if you do not want the waiting and pause on screen, remove this line.
# That's the standard way Read-Host works.
$SysName = Read-Host -prompt "Enter the target computer name: "
One possible solution:
param(
[switch]$manual
)
if($manual){
$SysName = Read-Host -prompt "Enter the target computer name: "
}else{
$SysName = "value or variable"
}
With this solution you can call your script using .\script.ps1 for auto-solution or .\script.ps1 -manual for the Read-Host.

Assistance in properly scripting a Join and Un-Join Domain script

Hello guys i have started to create a script that would basically automate the un-join and joining of a computer via a script this initially works fine right up until the point i need to start pinging for the computer to come back online. For the instance of un-joining it works fine but all the issue arise when trying to join.
Maybe fresh pair of eyes can lend me some Intel on the matter thank you.
<#
############################################################################################################
# Written by CPineda # NOTE: This only works if computer is on the wire. #
# This Script un-joins and re-joins the domain. # So its very important that we connect the devce #
# Created: 04/27/2016 # to the LAN. #
# Last revision 4/6/2016 # #
############################################################################################################
#>
# Set up your Variables
$ComputerIP = "" #Stores the Computers IP
$ComputerName = "" #Stores the Name of the computer you will be working with.
#$LocalCredentials = "" #Stores the Local Administrator credentials. (As Neeeded)
$DomainCredentials = "" #Stores the Domain Administrator credentials.
# Get information needed for the script to run.
while ($ComputerIP -eq ""){
Clear-Host #Clear the PS Console Window
$ComputerIP = Read-Host "Enter the name of the Computer IP"
}
while ($ComputerName -eq ""){
Clear-Host #Clear the PS Console Window
$ComputerName = Read-Host "Enter the name of the Computer"
}
<# while ($LocalCredentials -eq ""){
Clear-Host #Clear the PS Console Window
$LocalCredentials = Read-Host "Enter the User name of the Local User Admin Account"
}
#>
while ($DomainCredentials -eq ""){
Clear-Host #Clear the PS Console Window
$DomainCredentials = Read-Host "Enter the User name of the Domain User Admin Account"
}
# Remove the computer from the Domain.
Remove-Computer -ComputerName $ComputerName -LocalCredential $ComputerName\administrator -UnJoinDomainCredential kelsonfla\$DomainCredentials -WorkgroupName WORKGROUP -Force -Restart
Read-Host "Hit ENTER to continue"
# Ping until computer returns on the wire.
Clear-Host
Write-Host "At this time we will ping the compputer in question untill it returns back online"
Write-Host "Hit ENTER to continue"
Read-Host
Test-Connection ($ComputerIP) {
$result = Test-Connection $ComputerIP -Count 3 -Delay 10 -Quiet
if ($Result | where { $_ -match 'Reply from ' }){$true}
else {$false}
}
Write-Verbose "The computer $ComputerIP has went down for a reboot. Waiting for it to come back up..."
while (!(Test-Connection -ComputerName $ComputerIP)) {
Start-Sleep -Seconds 5
Write-Verbose "Waiting for $ComputerIP to come back online"
}
Write-Verbose "The computer $ComputerIP has come online. Waiting for OS to initialize"
$EapBefore = $ErrorActionPreference
$ErrorActionPreference = [System.Management.Automation.ActionPreference]::SilentlyContinue
while (!(Get-WmiObject -ComputerName $ComputerIP -Class Win32_OperatingSystem -Credential $LocalCredentials)) {
Start-Sleep -Seconds 5
Write-Verbose "Waiting for OS to initialize..."
$ErrorActionPreference = $EapBefore
}
# Add computer back to the Domain.
Add-Computer -ComputerName $ComputerIP -LocalCredential $ComputerName\administrator -DomainName kelsonfla.local -Credential kelsonfla\$DomainCredentials -Restart -Force
Read-Host "Hit ENTER to continue"
# Ping until computer returns on the wire.
Clear-Host
Write-Host "At this time we will ping the compputer in question untill it returns back online"
Write-Host "Hit ENTER to continue"
Read-Host
Test-Connection ($ComputerIP) {
$result = Test-Connection $ComputerIP -Count 3 -Delay 10 -Quiet
if ($Result | where { $_ -match 'Reply from ' }){$true}
else {$false}
}
Write-Verbose "The computer $ComputerIP has went down for a reboot. Waiting for it to come back up..."
while (!(Test-Connection -ComputerName $ComputerIP)) {
Start-Sleep -Seconds 5
Write-Verbose "Waiting for $ComputerIP to come back online"
}
Write-Verbose "The computer $ComputerIP has come online. Waiting for OS to initialize"
$EapBefore = $ErrorActionPreference
$ErrorActionPreference = [System.Management.Automation.ActionPreference]::SilentlyContinue
while (!(Get-WmiObject -ComputerName $ComputerIP -Class Win32_OperatingSystem -Credential $LocalCredentials)) {
Start-Sleep -Seconds 5
Write-Verbose "Waiting for OS to initialize..."
$ErrorActionPreference = $EapBefore
}
Clear-Host
Write-Output "If you are Reading this then you have successfully Unjoined and Re-Joined a Computer to the Network"
Start-Sleep -Seconds 3
Clear-Host
First : for the ping part, you should remove the code :
Test-Connection ($ComputerIP) {
$Result = ping $ComputerIP -n 3
if ($Result | where { $_ -match 'Reply from ' }) {
$true
} else {
$false
}
}
and simply use
!$result = $false
do {
Write-Verbose "Waiting for $ComputerIP to come back online"
$result = Test-Connection $ComputerIP -Count 2 -Delay 5 -Quiet
} while (!$result)
And then use the value of the $result boolean to see if your computer is reponding again. Test-Connection is a Cmdlet that cover the ping role.

User Logon/Logoff Information using Powershell

I want to be able to check a remote computer's user logon/logoff sessions and times and I have the following code that I got from stackoverflow, but I cannot figure out how to tell the script to check a remote computer:
$UserProperty = #{n="User";e={(New-Object System.Security.Principal.SecurityIdentifier
$_.ReplacementStrings[1]).Translate([System.Security.Principal.NTAccount])}}
$TypeProperty = #{n="Action";e={if($_.EventID -eq 7001) {"Logon"} else {"Logoff"}}}
$TimeProeprty = #{n="Time";e={$_.TimeGenerated}}
Get-EventLog System -Source Microsoft-Windows-Winlogon | select $UserProperty,$TypeProperty,$TimeProeprty
I did do throw in a $Computername variable and a Foreach loop statment like in the following to try and get it to run on a remote computer, but it keeps checking the local system that I am on, not the remote system:
$Computername = Read-Host "Enter Computername Here"
Foreach $Computer in $Computername
{
$UserProperty = #{n="User";e={(New-Object System.Security.Principal.SecurityIdentifier $_.ReplacementStrings[1]).Translate([System.Security.Principal.NTAccount])}}
$TypeProperty = #{n="Action";e={if($_.EventID -eq 7001) {"Logon"} else {"Logoff"}}}
$TimeProeprty = #{n="Time";e={$_.TimeGenerated}}
Get-EventLog System -Source Microsoft-Windows-Winlogon | select $UserProperty,$TypeProperty,$TimeProeprty
}
I know this is an old question, but no answer was ever accepted. One of the problems is that the script doesn't show which machine the user was logged into. Anyway, I fixed it up (including the typo).
Get-LogonHistory.ps1:
param(
[alias("CN")]
$ComputerName="localhost"
)
$UserProperty = #{n="User";e={(New-Object System.Security.Principal.SecurityIdentifier $_.ReplacementStrings[1]).Translate([System.Security.Principal.NTAccount])}}
$TypeProperty = #{n="Action";e={if($_.EventID -eq 7001) {"Logon"} else {"Logoff"}}}
$TimeProperty = #{n="Time";e={$_.TimeGenerated}}
$MachineNameProperty = #{n="MachinenName";e={$_.MachineName}}
foreach ($computer in $ComputerName) {
Get-EventLog System -Source Microsoft-Windows-Winlogon -ComputerName $computer | select $UserProperty,$TypeProperty,$TimeProperty,$MachineNameProperty
}
With this, it will show which machine the user logged into. Multiple remote computers can be passed into the command line with commas between each (no spaces).
You need to use the Get-EventLog cmdlet's ComputerName parameter:
Get-EventLog -ComputerName $Computer System -Source Microsoft-Windows-Winlogon `
| select $UserProperty,$TypeProperty,$TimeProeprty
Also, it looks like you have a typo in your $TimeProeprty variable.
A bit modified and its working
# Specify the location you want the report to be saved
$filelocation = "C:\report.csv"
[void][System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic')
[string]$Computer = [Microsoft.VisualBasic.Interaction]::InputBox("Enter ComputerName", "Computer Name", "Computer Name")
[int]$DayPrompt = [Microsoft.VisualBasic.Interaction]::InputBox("Enter Number of Days to check", "Days to Check", "15")
$Days = $DayPrompt
cls
$Result = #()
Write-Host "Gathering Event Logs, this can take awhile..."
$ELogs = Get-EventLog System -Source Microsoft-Windows-WinLogon -After (Get-Date).AddDays(- $Days) -ComputerName $Computer
If ($ELogs)
{ Write-Host "Processing..."
ForEach ($Log in $ELogs)
{ If ($Log.InstanceId -eq 7001)
{ $ET = "Logon"
}
ElseIf ($Log.InstanceId -eq 7002)
{ $ET = "Logoff"
}
Else
{ Continue
}
$Result += New-Object PSObject -Property #{
Time = $Log.TimeWritten
'Event Type' = $ET
User = (New-Object System.Security.Principal.SecurityIdentifier $Log.ReplacementStrings[1]).Translate([System.Security.Principal.NTAccount])
}
}
$Result | Select Time,"Event Type",User | Sort Time -Descending | Export-CSV $filelocation
Write-Host "Done look at $filelocation"
}
Else
{ Write-Host "Problem with $Computer."
Write-Host "If you see a 'Network Path not found' error, try starting the Remote Registry service on that computer."
Write-Host "Or there are no logon/logoff events (XP requires auditing be turned on)"
}
You're not passing the computer name to any command in the loop. So it's just looping through the same command for as many objects are in $computerName Try changing the last line to this:
Get-EventLog System -Source Microsoft-Windows-Winlogon -ComputerName $computer | select $UserProperty,$TypeProperty,$TimeProperty
If that doesn't work, make sure that your foreach loop is passing the right data:
$computerName | Foreach-Object{Write-Host $_}
That should display the computer name of each of the machine's you're trying to run this on.
But it looks like you're trying to run it for one computer, so remove the Foreach loop and just add -ComputerName $computername to the end of the Get-Eventlog command before your select statement
Based on https://gallery.technet.microsoft.com/Log-Parser-to-Identify-8aac36bd
Get-Eventlog -LogName Security | where {$_.EventId -eq "4624"} | select-object #{Name="User"
;Expression={$_.ReplacementStrings[5]}} | sort-object User -unique
You can grab other info from ReplacementStrings. You can also specify a remote computer in the Get-Eventlog command.
# Specify the location you want the report to be saved
$filelocation = "C:\Path\report.csv"
[void][System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic')
[string]$Computer = [Microsoft.VisualBasic.Interaction]::InputBox("Enter ComputerName", "Computer Name", "Computer Name")
[int]$DayPrompt = [Microsoft.VisualBasic.Interaction]::InputBox("Enter Number of Days to check", "Days to Check", "15")
$Days = $DayPrompt
cls
$Result = #()
Write-Host "Gathering Event Logs, this can take awhile..."
$ELogs = Get-EventLog System -Source Microsoft-Windows-WinLogon -After (Get-Date).AddDays(- $Days) -ComputerName $Computer
If ($ELogs)
{ Write-Host "Processing..."
ForEach ($Log in $ELogs)
{ If ($Log.InstanceId -eq 7001)
{ $ET = "Logon"
}
ElseIf ($Log.InstanceId -eq 7002)
{ $ET = "Logoff"
}
Else
{ Continue
}
$Result += New-Object PSObject -Property #{
Time = $Log.TimeWritten
'Event Type' = $ET
User = (New-Object System.Security.Principal.SecurityIdentifier $Log.ReplacementStrings[1]).Translate([System.Security.Principal.NTAccount])
}
}
$Result | Select Time,"Event Type",User | Sort Time -Descending | Export-CSV $filelocation - TypeInformation
Write-Host "Done."
}
Else
{ Write-Host "Problem with $Computer."
Write-Host "If you see a 'Network Path not found' error, try starting the Remote Registry service on that computer."
Write-Host "Or there are no logon/logoff events (XP requires auditing be turned on)"
}